// unit.cpp

#include "CvGameCoreDLL.h"
#include "CvUnit.h"
#include "CvArea.h"
#include "CvPlot.h"
#include "CvCity.h"
#include "CvGlobals.h"
#include "CvGameCoreUtils.h"
#include "CvGameAI.h"
#include "CvMap.h"
#include "CvPlayerAI.h"
#include "CvRandom.h"
#include "CvTeamAI.h"
#include "CvGameCoreUtils.h"
#include "CyUnit.h"
#include "CyArgsList.h"
#include "CyPlot.h"
#include "CvDLLEntityIFaceBase.h"
#include "CvDLLInterfaceIFaceBase.h"
#include "CvDLLEngineIFaceBase.h"
#include "CvDLLEventReporterIFaceBase.h"
#include "CvDLLPythonIFaceBase.h"
#include "CvDLLFAStarIFaceBase.h"
#include "CvInfos.h"
#include "FProfiler.h"
#include "CvPopupInfo.h"
#include "CvArtFileMgr.h"

// Public Functions...


CvUnit::CvUnit()
{
	m_aiExtraDomainModifier = new int[NUM_DOMAIN_TYPES];

//FfH Damage Types: Added by Kael 08/23/2007
	m_paiBonusAffinity = NULL;
	m_paiBonusAffinityAmount = NULL;
	m_paiDamageTypeCombat = NULL;
	m_paiDamageTypeResist = NULL;
//FfH: End Add

	m_pabHasPromotion = NULL;

	m_paiTerrainDoubleMoveCount = NULL;
	m_paiFeatureDoubleMoveCount = NULL;
	m_paiExtraTerrainAttackPercent = NULL;
	m_paiExtraTerrainDefensePercent = NULL;
	m_paiExtraFeatureAttackPercent = NULL;
	m_paiExtraFeatureDefensePercent = NULL;
	m_paiExtraUnitCombatModifier = NULL;

/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**											Clears Arrays										**/
/*************************************************************************************************/
	m_piYieldFromWin = NULL;
	m_piYieldForLoss = NULL;
	m_piCommerceFromWin = NULL;
	m_piCommerceForLoss = NULL;
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
	CvDLLEntity::createUnitEntity(this);		// create and attach entity to unit

	reset(0, NO_UNIT, NO_PLAYER, true);
}


CvUnit::~CvUnit()
{
	if (!gDLL->GetDone() && GC.IsGraphicsInitialized())						// don't need to remove entity when the app is shutting down, or crash can occur
	{
		gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
		CvDLLEntity::removeEntity();		// remove entity from engine
	}

	CvDLLEntity::destroyEntity();			// delete CvUnitEntity and detach from us

	uninit();

	SAFE_DELETE_ARRAY(m_aiExtraDomainModifier);
}

void CvUnit::reloadEntity()
{
	//destroy old entity
	if (!gDLL->GetDone() && GC.IsGraphicsInitialized())						// don't need to remove entity when the app is shutting down, or crash can occur
	{
		gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
		CvDLLEntity::removeEntity();		// remove entity from engine
	}

	CvDLLEntity::destroyEntity();			// delete CvUnitEntity and detach from us

	//creat new one
	CvDLLEntity::createUnitEntity(this);		// create and attach entity to unit
	setupGraphical();
}


void CvUnit::init(int iID, UnitTypes eUnit, UnitAITypes eUnitAI, PlayerTypes eOwner, int iX, int iY, DirectionTypes eFacingDirection)
{
	CvWString szBuffer;
	int iUnitName;
	int iI, iJ;

	FAssert(NO_UNIT != eUnit);

	//--------------------------------
	// Init saved data
	reset(iID, eUnit, eOwner);

	if(eFacingDirection == NO_DIRECTION)
		m_eFacingDirection = DIRECTION_SOUTH;
	else
		m_eFacingDirection = eFacingDirection;

	//--------------------------------
	// Init containers

	//--------------------------------
	// Init pre-setup() data
	setXY(iX, iY, false, false);

	//--------------------------------
	// Init non-saved data
	setupGraphical();

	//--------------------------------
	// Init other game data
	plot()->updateCenterUnit();

	plot()->setFlagDirty(true);

	iUnitName = GC.getGameINLINE().getUnitCreatedCount(getUnitType());
	int iNumNames = m_pUnitInfo->getNumUnitNames();
	if (iUnitName < iNumNames)
	{
		int iOffset = GC.getGameINLINE().getSorenRandNum(iNumNames, "Unit name selection");

		for (iI = 0; iI < iNumNames; iI++)
		{
			int iIndex = (iI + iOffset) % iNumNames;
			CvWString szName = gDLL->getText(m_pUnitInfo->getUnitNames(iIndex));
			if (!GC.getGameINLINE().isGreatPersonBorn(szName))
			{
				setName(szName);
				GC.getGameINLINE().addGreatPersonBornName(szName);
				break;
			}
		}
	}

	setGameTurnCreated(GC.getGameINLINE().getGameTurn());

	GC.getGameINLINE().incrementUnitCreatedCount(getUnitType());

	GC.getGameINLINE().incrementUnitClassCreatedCount((UnitClassTypes)(m_pUnitInfo->getUnitClassType()));
	GET_TEAM(getTeam()).changeUnitClassCount(((UnitClassTypes)(m_pUnitInfo->getUnitClassType())), 1);
	GET_PLAYER(getOwnerINLINE()).changeUnitClassCount(((UnitClassTypes)(m_pUnitInfo->getUnitClassType())), 1);

	GET_PLAYER(getOwnerINLINE()).changeExtraUnitCost(m_pUnitInfo->getExtraCost());

	if (m_pUnitInfo->getNukeRange() != -1)
	{
		GET_PLAYER(getOwnerINLINE()).changeNumNukeUnits(1);
	}

	if (m_pUnitInfo->isMilitarySupport())
	{
		GET_PLAYER(getOwnerINLINE()).changeNumMilitaryUnits(1);
	}

	GET_PLAYER(getOwnerINLINE()).changeAssets(m_pUnitInfo->getAssetValue());

	GET_PLAYER(getOwnerINLINE()).changePower(m_pUnitInfo->getPowerValue());

	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		if (m_pUnitInfo->getFreePromotions(iI))
		{
			setHasPromotion(((PromotionTypes)iI), true);
		}
	}

	FAssertMsg((GC.getNumTraitInfos() > 0), "GC.getNumTraitInfos() is less than or equal to zero but is expected to be larger than zero in CvUnit::init");
	for (iI = 0; iI < GC.getNumTraitInfos(); iI++)
	{
		if (GET_PLAYER(getOwnerINLINE()).hasTrait((TraitTypes)iI))
		{
			for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
			{
				if (GC.getTraitInfo((TraitTypes) iI).isFreePromotion(iJ))
				{
					if ((getUnitCombatType() != NO_UNITCOMBAT) && GC.getTraitInfo((TraitTypes) iI).isFreePromotionUnitCombat(getUnitCombatType()))
					{
						setHasPromotion(((PromotionTypes)iJ), true);
					}
				}
			}
		}
	}

	if (NO_UNITCOMBAT != getUnitCombatType())
	{
		for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
		{
			if (GET_PLAYER(getOwnerINLINE()).isFreePromotion(getUnitCombatType(), (PromotionTypes)iJ))
			{
				setHasPromotion(((PromotionTypes)iJ), true);
			}
		}
	}

	if (NO_UNITCLASS != getUnitClassType())
	{
		for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
		{
			if (GET_PLAYER(getOwnerINLINE()).isFreePromotion(getUnitClassType(), (PromotionTypes)iJ))
			{
				setHasPromotion(((PromotionTypes)iJ), true);
			}
		}
	}

	if (getDomainType() == DOMAIN_LAND)
	{
		if (baseCombatStr() > 0)
		{
			if ((GC.getGameINLINE().getBestLandUnit() == NO_UNIT) || (baseCombatStr() > GC.getGameINLINE().getBestLandUnitCombat()))
			{
				GC.getGameINLINE().setBestLandUnit(getUnitType());
			}
		}
	}

	if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
	{
		gDLL->getInterfaceIFace()->setDirty(GameData_DIRTY_BIT, true);
	}

	if (isWorldUnitClass((UnitClassTypes)(m_pUnitInfo->getUnitClassType()))

//FfH: Added by Kael 11/05/2007
      && GC.getGameINLINE().getUnitClassCreatedCount((UnitClassTypes)(m_pUnitInfo->getUnitClassType())) == 1
//FfH: End Add

	)
	{
		for (iI = 0; iI < MAX_PLAYERS; iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive())
			{
				if (GET_TEAM(getTeam()).isHasMet(GET_PLAYER((PlayerTypes)iI).getTeam()))
				{
					szBuffer = gDLL->getText("TXT_KEY_MISC_SOMEONE_CREATED_UNIT", GET_PLAYER(getOwnerINLINE()).getNameKey(), getNameKey());
					gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"), getX_INLINE(), getY_INLINE(), true, true);
				}
				else
				{
					szBuffer = gDLL->getText("TXT_KEY_MISC_UNKNOWN_CREATED_UNIT", getNameKey());
					gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"));
				}
			}
		}

		szBuffer = gDLL->getText("TXT_KEY_MISC_SOMEONE_CREATED_UNIT", GET_PLAYER(getOwnerINLINE()).getNameKey(), getNameKey());
		GC.getGameINLINE().addReplayMessage(REPLAY_MESSAGE_MAJOR_EVENT, getOwnerINLINE(), szBuffer, getX_INLINE(), getY_INLINE(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"));
	}

	AI_init(eUnitAI);

//FfH Units: Added by Kael 04/18/2008
	if (m_pUnitInfo->getFreePromotionPick() > 0)
	{
	    changeFreePromotionPick(m_pUnitInfo->getFreePromotionPick());
        setPromotionReady(true);
    }
    GC.getGameINLINE().changeGlobalCounter(m_pUnitInfo->getModifyGlobalCounter());
	m_iReligion = m_pUnitInfo->getReligionType();
    for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
    {
        changeBonusAffinity((BonusTypes)iI, m_pUnitInfo->getBonusAffinity((BonusTypes)iI));
    }
    if (m_pUnitInfo->isMechUnit())
    {
        setAlive(false);
    }
    if (GC.getCivilizationInfo(getCivilizationType()).getDefaultRace() != NO_PROMOTION)
    {
        if (getRace() == NO_PROMOTION)
        {
//WH: Ploeperpengel modify
			if (!::isWorldUnitClass(getUnitClassType()) && !isAnimal() && isAlive() && getDomainType() == DOMAIN_LAND && getUnitCombatType()!= GC.getInfoTypeForString("UNITCOMBAT_BEAST"))
//WH: end modify
			{
                setHasPromotion((PromotionTypes)GC.getCivilizationInfo(getCivilizationType()).getDefaultRace(), true);
            }
        }
    }
//FfH: End Add
/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**							Loads Information from the UnitType to the Unit						**/
/*************************************************************************************************/
    for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
    {
        changeYieldForLoss(iI, m_pUnitInfo->getYieldFromKill(iI));
    }

    for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
    {
        changeCommerceForLoss(iI, m_pUnitInfo->getCommerceFromKill(iI));
    }
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/

	gDLL->getEventReporterIFace()->unitCreated(this);
}


void CvUnit::uninit()
{

//FfH Damage Types: Added by Kael 08/23/2007
	SAFE_DELETE_ARRAY(m_paiBonusAffinity);
	SAFE_DELETE_ARRAY(m_paiBonusAffinityAmount);
	SAFE_DELETE_ARRAY(m_paiDamageTypeCombat);
	SAFE_DELETE_ARRAY(m_paiDamageTypeResist);
//FfH: End Add

	SAFE_DELETE_ARRAY(m_pabHasPromotion);

	SAFE_DELETE_ARRAY(m_paiTerrainDoubleMoveCount);
	SAFE_DELETE_ARRAY(m_paiFeatureDoubleMoveCount);
	SAFE_DELETE_ARRAY(m_paiExtraTerrainAttackPercent);
	SAFE_DELETE_ARRAY(m_paiExtraTerrainDefensePercent);
	SAFE_DELETE_ARRAY(m_paiExtraFeatureAttackPercent);
	SAFE_DELETE_ARRAY(m_paiExtraFeatureDefensePercent);
	SAFE_DELETE_ARRAY(m_paiExtraUnitCombatModifier);
/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**											Clears Arrays										**/
/*************************************************************************************************/
	SAFE_DELETE_ARRAY(m_piYieldFromWin);
	SAFE_DELETE_ARRAY(m_piYieldForLoss);
	SAFE_DELETE_ARRAY(m_piCommerceFromWin);
	SAFE_DELETE_ARRAY(m_piCommerceForLoss);
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
}


// FUNCTION: reset()
// Initializes data members that are serialized.
void CvUnit::reset(int iID, UnitTypes eUnit, PlayerTypes eOwner, bool bConstructorCall)
{
	int iI;

	//--------------------------------
	// Uninit class
	uninit();

	m_iID = iID;
	m_iGroupID = FFreeList::INVALID_INDEX;
	m_iHotKeyNumber = -1;
	m_iX = INVALID_PLOT_COORD;
	m_iY = INVALID_PLOT_COORD;
	m_iLastMoveTurn = 0;
	m_iReconX = INVALID_PLOT_COORD;
	m_iReconY = INVALID_PLOT_COORD;
	m_iGameTurnCreated = 0;
	m_iDamage = 0;
	m_iMoves = 0;
	m_iExperience = 0;
	m_iLevel = 1;
	m_iCargo = 0;
	m_iAttackPlotX = INVALID_PLOT_COORD;
	m_iAttackPlotY = INVALID_PLOT_COORD;
	m_iCombatTimer = 0;
	m_iCombatFirstStrikes = 0;
	m_iCombatDamage = 0;
	m_iFortifyTurns = 0;
	m_iBlitzCount = 0;
	m_iAmphibCount = 0;
	m_iRiverCount = 0;
/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**										Set Intial Values										**/
/*************************************************************************************************/
	m_iTerritorialCount = 0;
	m_iRivalTerritoryExploreCount = 0;
	m_iRivalTerritoryBlockCount = 0;
	m_iPillageOnMoveCount = 0;
	m_iSelfPillageCount = 0;
	m_iGetCasterXPCount = 0;
	m_iNonWarWearinessCount = 0;
	m_iNoMapRevealCount = 0;
	m_iCannotCaptureCount = 0;
	m_iCityHappyCount = 0;
	m_iCityNoHappyCount = 0;
	m_iNoSupportCount = 0;
	m_iCanPillageCount = 0;
	m_iCannotPillageCount = 0;
	m_iCitySpyCount = 0;
	m_iStartGoldenAgeCount = 0;
	m_iNoDefenseBonusCount = 0;
	m_iMoveImpassableCount = 0;
	m_iFlatMoveCostCount = 0;
	m_iIgnoreTerrainCostsCount = 0;
	m_iAttackNoWarCount = 0;
	m_iAllowAttacksCount = 0;
	m_iFirstStrikeVulnerableCount = 0;
	m_iAllowDefenseBonusesCount = 0;
	m_iNonAbandonCount = 0;
	m_iIndependantCount = 0;

	m_iWorkRateChange = 0;
	m_iCombatConversionChance = 0;
	m_iCombatUnitGenerationChance = 0;
	m_iSlaveGenerationChance = 0;
	m_iGiftableXP = 0;
	m_iCombatExtraDuration = 0;
	m_iDurationPerTurn = 0;
	m_iChangeDuration = 0;
	m_bNonTemporary = false;
	m_iExtraSupport = 0;
	m_iChanceMiscast = 0;
	m_iCombatDmgCap = 0;
	m_iCombatDmgCapBoost = 0;
	m_iCollateralLimitCap = 0;
	m_iCollateralLimitBoost = 0;
	m_iCollateralTargetsLimit = 0;
	m_iCollateralExtraTargets = 0;
	m_iHammerSacrifice = 0;
	m_iExtraHammerPerPop = 0;
	m_iFoodSacrifice = 0;
	m_iPopulationAdd = 0;
	m_iBeakerSacrifice = 0;
	m_iExtraBeakerPerPop = 0;
	m_iGoldSacrifice = 0;
	m_iExtraGoldPerPop = 0;
	m_iCultureSacrifice = 0;
	m_iExtraCulturePerPop = 0;
	if (!bConstructorCall)
	{
        m_piYieldFromWin = new int[NUM_YIELD_TYPES];
        m_piYieldForLoss = new int[NUM_YIELD_TYPES];
        for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
        {
            m_piYieldFromWin[iI] = 0;
            m_piYieldForLoss[iI] = 0;
        }
        m_piCommerceFromWin = new int[NUM_COMMERCE_TYPES];
        m_piCommerceForLoss = new int[NUM_COMMERCE_TYPES];
        for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
        {
            m_piCommerceFromWin[iI] = 0;
            m_piCommerceForLoss[iI] = 0;
        }
	}
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
	m_iEnemyRouteCount = 0;
	m_iAlwaysHealCount = 0;
	m_iHillsDoubleMoveCount = 0;
	m_iImmuneToFirstStrikesCount = 0;
	m_iExtraVisibilityRange = 0;
	m_iExtraMoves = 0;
	m_iExtraMoveDiscount = 0;
	m_iExtraAirRange = 0;
	m_iExtraIntercept = 0;
	m_iExtraEvasion = 0;
	m_iExtraFirstStrikes = 0;
	m_iExtraChanceFirstStrikes = 0;
	m_iExtraWithdrawal = 0;
	m_iExtraCollateralDamage = 0;
	m_iExtraBombardRate = 0;
	m_iExtraEnemyHeal = 0;
	m_iExtraNeutralHeal = 0;
	m_iExtraFriendlyHeal = 0;
	m_iSameTileHeal = 0;
	m_iAdjacentTileHeal = 0;
	m_iExtraCombatPercent = 0;
	m_iExtraCityAttackPercent = 0;
	m_iExtraCityDefensePercent = 0;
	m_iExtraHillsAttackPercent = 0;
	m_iExtraHillsDefensePercent = 0;
	m_iRevoltProtection = 0;
	m_iCollateralDamageProtection = 0;
	m_iPillageChange = 0;
	m_iUpgradeDiscount = 0;
	m_iExperiencePercent = 0;
	m_iKamikazePercent = 0;
	m_eFacingDirection = DIRECTION_SOUTH;
	m_iImmobileTimer = 0;

	m_bMadeAttack = false;
	m_bMadeInterception = false;
	m_bPromotionReady = false;
	m_bDeathDelay = false;
	m_bCombatFocus = false;
	m_bInfoBarDirty = false;
	m_bBlockading = false;
	m_bAirCombat = false;

	m_eOwner = eOwner;
	m_eCapturingPlayer = NO_PLAYER;
	m_eUnitType = eUnit;
	m_pUnitInfo = (NO_UNIT != m_eUnitType) ? &GC.getUnitInfo(m_eUnitType) : NULL;
	m_iBaseCombat = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getCombat() : 0;
	m_eLeaderUnitType = NO_UNIT;
	m_iCargoCapacity = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getCargoSpace() : 0;

//FfH Spell System: Added by Kael 07/23/2007
	m_bAlive = true;
	m_bBoarding = false;
	m_bDoubleFortifyBonus = false;
	m_bFear = false;
	m_bFleeImmortal = false;
	m_bFleeWithdrawl = false;
	m_bFlying = false;
	m_bHasCasted = false;
	m_bHiddenNationality = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->isHiddenNationality() : false;
	m_bIgnoreBuildingDefense = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->isIgnoreBuildingDefense() : false;
	m_bImmortal = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->isImmortal() : false;
	m_bImmuneToCapture = false;
	m_bImmuneToFear = false;
	m_bImmuneToMagic = false;
	m_bOnlyDefensive = false;
	m_bTargetWeakestUnit = false;
	m_bTargetWeakestUnitCounter = false;
	m_bTwincast = false;
	m_bWaterWalking = false;
	m_iBaseCombatDefense = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getCombatDefense() : 0;
	m_iBetterDefenderThanPercent = 100;
	m_iCombatHealPercent = 0;
	m_iCombatLimit = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getCombatLimit() : 0;
	m_iCombatPercentInBorders = 0;
	m_iCombatPercentGlobalCounter = 0;
	m_iDelayedSpell = NO_SPELL;
	m_iDuration = 0;
	m_iFreePromotionPick = 0;
	m_iGroupSize = 0;
	m_iInvisibleType = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getInvisibleType() : 0;
	m_iRace = NO_PROMOTION;
    m_iReligion = NO_RELIGION;
	m_iResist = 0;
	m_iResistModify = 0;
	m_iSpellCasterXP = 0;
	m_iSpellDamageModify = 0;
	m_iTotalDamageTypeCombat = 0;
    m_iUnitArtStyleType = NO_UNIT_ARTSTYLE;

	if (!bConstructorCall)
	{
        m_paiDamageTypeCombat = new int[GC.getNumDamageTypeInfos()];
        m_paiDamageTypeResist = new int[GC.getNumDamageTypeInfos()];
        for (iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
        {
            int iChange = (NO_UNIT != m_eUnitType) ? m_pUnitInfo->getDamageTypeCombat(iI) : 0;
            m_paiDamageTypeCombat[iI] = iChange;
            m_paiDamageTypeResist[iI] = 0;
            m_iTotalDamageTypeCombat += iChange;
        }
        m_paiBonusAffinity = new int[GC.getNumBonusInfos()];
        m_paiBonusAffinityAmount = new int[GC.getNumBonusInfos()];
        for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
        {
            m_paiBonusAffinity[iI] = 0;
            m_paiBonusAffinityAmount[iI] = 0;
        }
	}
//FfH: End Add

	m_combatUnit.reset();
	m_transportUnit.reset();

	for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
	{
		m_aiExtraDomainModifier[iI] = 0;
	}

	clear(m_szName);
	m_szScriptData ="";

	if (!bConstructorCall)
	{
		FAssertMsg((0 < GC.getNumPromotionInfos()), "GC.getNumPromotionInfos() is not greater than zero but an array is being allocated in CvUnit::reset");
		m_pabHasPromotion = new bool[GC.getNumPromotionInfos()];
		for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
		{
			m_pabHasPromotion[iI] = false;
		}

		FAssertMsg((0 < GC.getNumTerrainInfos()), "GC.getNumTerrainInfos() is not greater than zero but a float array is being allocated in CvUnit::reset");
		m_paiTerrainDoubleMoveCount = new int[GC.getNumTerrainInfos()];
		m_paiExtraTerrainAttackPercent = new int[GC.getNumTerrainInfos()];
		m_paiExtraTerrainDefensePercent = new int[GC.getNumTerrainInfos()];
		for (iI = 0; iI < GC.getNumTerrainInfos(); iI++)
		{
			m_paiTerrainDoubleMoveCount[iI] = 0;
			m_paiExtraTerrainAttackPercent[iI] = 0;
			m_paiExtraTerrainDefensePercent[iI] = 0;
		}

		FAssertMsg((0 < GC.getNumFeatureInfos()), "GC.getNumFeatureInfos() is not greater than zero but a float array is being allocated in CvUnit::reset");
		m_paiFeatureDoubleMoveCount = new int[GC.getNumFeatureInfos()];
		m_paiExtraFeatureDefensePercent = new int[GC.getNumFeatureInfos()];
		m_paiExtraFeatureAttackPercent = new int[GC.getNumFeatureInfos()];
		for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
		{
			m_paiFeatureDoubleMoveCount[iI] = 0;
			m_paiExtraFeatureAttackPercent[iI] = 0;
			m_paiExtraFeatureDefensePercent[iI] = 0;
		}

		FAssertMsg((0 < GC.getNumUnitCombatInfos()), "GC.getNumUnitCombatInfos() is not greater than zero but an array is being allocated in CvUnit::reset");
		m_paiExtraUnitCombatModifier = new int[GC.getNumUnitCombatInfos()];
		for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
		{
			m_paiExtraUnitCombatModifier[iI] = 0;
		}

		AI_reset();
	}
}


//////////////////////////////////////
// graphical only setup
//////////////////////////////////////
void CvUnit::setupGraphical()
{
	if (!GC.IsGraphicsInitialized())
	{
		return;
	}

	CvDLLEntity::setup();

	if (getGroup()->getActivityType() == ACTIVITY_INTERCEPT)
	{
		airCircle(true);
	}
}


void CvUnit::convert(CvUnit* pUnit)
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pTransportUnit;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;
	int iI;

	pPlot = plot();

	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{

//FfH: Modified by Kael 07/30/2007
//		setHasPromotion(((PromotionTypes)iI), (pUnit->isHasPromotion((PromotionTypes)iI) || m_pUnitInfo->getFreePromotions(iI)));
//  }
        if (pUnit->isHasPromotion((PromotionTypes)iI))
        {
            if (iI == GC.getDefineINT("MUTATED_PROMOTION"))
            {
                m_pabHasPromotion[iI] = pUnit->isHasPromotion((PromotionTypes)iI);
            }
            else
            {
                setHasPromotion(((PromotionTypes)iI), true);
                if (GC.getPromotionInfo((PromotionTypes)iI).isEquipment())
                {
                    pUnit->setHasPromotion((PromotionTypes)iI, false);
                }
            }
            if (GC.getPromotionInfo((PromotionTypes)iI).isValidate())
            {
                if (!GC.getPromotionInfo((PromotionTypes)iI).getUnitCombat(getUnitCombatType()))
                {
                    setHasPromotion(((PromotionTypes)iI), false);
                }
            }
        }
    }
    if (GC.getDefineINT("WEAPON_PROMOTION_TIER1") != -1 && isHasPromotion((PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER1")))
    {
        if (m_pUnitInfo->getWeaponTier() < 1)
        {
            setHasPromotion((PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER1"), false);
        }
    }
    if (GC.getDefineINT("WEAPON_PROMOTION_TIER2") != -1 && isHasPromotion((PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER2")))
    {
        if (m_pUnitInfo->getWeaponTier() < 2)
        {
            setHasPromotion((PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER2"), false);
        }
    }
    if (GC.getDefineINT("WEAPON_PROMOTION_TIER3") != -1 && isHasPromotion((PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER3")))
    {
        if (m_pUnitInfo->getWeaponTier() < 3)
        {
            setHasPromotion((PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER3"), false);
        }
    }
    if (m_pUnitInfo->getFreePromotionPick() > 0 && getGameTurnCreated() == GC.getGameINLINE().getGameTurn())
	{
	    changeFreePromotionPick(m_pUnitInfo->getFreePromotionPick());
        setPromotionReady(true);
    }
    setDuration(pUnit->getDuration());
    if (pUnit->getReligion() != NO_RELIGION && getReligion() == NO_RELIGION)
    {
        setReligion(pUnit->getReligion());
    }
//FfH: End Modify

	setGameTurnCreated(pUnit->getGameTurnCreated());
	setDamage(pUnit->getDamage());
	setMoves(pUnit->getMoves());

	setLevel(pUnit->getLevel());
	int iOldModifier = std::max(1, 100 + GET_PLAYER(pUnit->getOwnerINLINE()).getLevelExperienceModifier());
	int iOurModifier = std::max(1, 100 + GET_PLAYER(getOwnerINLINE()).getLevelExperienceModifier());
	setExperience(std::max(0, (pUnit->getExperience() * iOurModifier) / iOldModifier));

	setName(pUnit->getNameNoDesc());
	setLeaderUnitType(pUnit->getLeaderUnitType());

	pTransportUnit = pUnit->getTransportUnit();

	if (pTransportUnit != NULL)
	{
		pUnit->setTransportUnit(NULL);
		setTransportUnit(pTransportUnit);
	}

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == pUnit)
		{
			pLoopUnit->setTransportUnit(this);
		}
	}

	pUnit->kill(true);
}


void CvUnit::kill(bool bDelay, PlayerTypes ePlayer)
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pTransportUnit;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;
	CvWString szBuffer;
	PlayerTypes eOwner;
	PlayerTypes eCapturingPlayer;
	UnitTypes eCaptureUnitType;

	pPlot = plot();
	FAssertMsg(pPlot != NULL, "Plot is not assigned a valid value");

	static std::vector<IDInfo> oldUnits;
	oldUnits.erase(oldUnits.begin(), oldUnits.end());
	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		oldUnits.push_back(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);
	}
	for(int i=0;i<(int)oldUnits.size();i++)
	{
		pLoopUnit = ::getUnit(oldUnits[i]);

		if (pLoopUnit != NULL)
		{
			if (pLoopUnit->getTransportUnit() == this)
			{
				//save old units because kill will clear the static list
				std::vector<IDInfo> tempUnits = oldUnits;

				if (pPlot->isValidDomainForLocation(*pLoopUnit))
				{
					pLoopUnit->setCapturingPlayer(getCapturingPlayer());
				}

				pLoopUnit->kill(false, ePlayer);

				oldUnits = tempUnits;
			}
		}
	}

	if (ePlayer != NO_PLAYER)
	{
        gDLL->getEventReporterIFace()->unitKilled(this, ePlayer);
		if (NO_UNIT != getLeaderUnitType())
		{
			for (int iI = 0; iI < MAX_PLAYERS; iI++)
			{
				if (GET_PLAYER((PlayerTypes)iI).isAlive())
				{
					szBuffer = gDLL->getText("TXT_KEY_MISC_GENERAL_KILLED", getNameKey());
					gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_MAJOR_EVENT);
				}
			}
		}
	}

	if (bDelay)
	{
		startDelayedDeath();
		return;
	}

//FfH Units: Added by Kael 08/09/2007
    GC.getGameINLINE().changeGlobalCounter(-1 * m_pUnitInfo->getModifyGlobalCounter());
	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
	    if (isHasPromotion((PromotionTypes)iI))
	    {
            GC.getGameINLINE().changeGlobalCounter(-1 * GC.getPromotionInfo((PromotionTypes)iI).getModifyGlobalCounter());
            if (GC.getPromotionInfo((PromotionTypes)iI).isEquipment())
            {
                for (int iJ = 0; iJ < GC.getNumUnitInfos(); iJ++)
                {
                    if (GC.getUnitInfo((UnitTypes)iJ).getEquipmentPromotion() == iI)
                    {
                        GET_PLAYER(getOwnerINLINE()).initUnit((UnitTypes)iJ, getX_INLINE(), getY_INLINE(), AI_getUnitAIType());
                        setHasPromotion((PromotionTypes)iI, false);
                    }
                }
            }
	    }
	}
	if (isWorldUnitClass((UnitClassTypes)(m_pUnitInfo->getUnitClassType())) && GC.getGameINLINE().getUnitClassCreatedCount((UnitClassTypes)(m_pUnitInfo->getUnitClassType())) == 1)
	{
		for (int iI = 0; iI < MAX_PLAYERS; iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive() && GET_PLAYER((PlayerTypes)iI).isHuman() && getOwner() != iI)
			{
                szBuffer = gDLL->getText("TXT_KEY_MISC_SOMEONE_KILLED_UNIT", getNameKey());
                gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"), getX_INLINE(), getY_INLINE(), true, true);
			}
		}
	}
//FfH: End Add

	if (isMadeAttack() && nukeRange() != -1)
	{
		CvPlot* pTarget = getAttackPlot();
		if (pTarget)
		{
			pTarget->nukeExplosion(nukeRange(), this);
			setAttackPlot(NULL, false);
		}
	}

	finishMoves();

	if (IsSelected())
	{
		if (gDLL->getInterfaceIFace()->getLengthSelectionList() == 1)
		{
			if (!(gDLL->getInterfaceIFace()->isFocused()) && !(gDLL->getInterfaceIFace()->isCitySelection()) && !(gDLL->getInterfaceIFace()->isDiploOrPopupWaiting()))
			{
				GC.getGameINLINE().updateSelectionList();
			}

			if (IsSelected())
			{
				gDLL->getInterfaceIFace()->setCycleSelectionCounter(1);
			}
			else
			{
				gDLL->getInterfaceIFace()->setDirty(SelectionCamera_DIRTY_BIT, true);
			}
		}
	}

	gDLL->getInterfaceIFace()->removeFromSelectionList(this);

	// XXX this is NOT a hack, without it, the game crashes.
	gDLL->getEntityIFace()->RemoveUnitFromBattle(this);

	FAssertMsg(!isCombat(), "isCombat did not return false as expected");

	pTransportUnit = getTransportUnit();

	if (pTransportUnit != NULL)
	{
		setTransportUnit(NULL);
	}

	setReconPlot(NULL);
	setBlockading(false);

	FAssertMsg(getAttackPlot() == NULL, "The current unit instance's attack plot is expected to be NULL");
	FAssertMsg(getCombatUnit() == NULL, "The current unit instance's combat unit is expected to be NULL");

	GET_TEAM(getTeam()).changeUnitClassCount((UnitClassTypes)m_pUnitInfo->getUnitClassType(), -1);
	GET_PLAYER(getOwnerINLINE()).changeUnitClassCount((UnitClassTypes)m_pUnitInfo->getUnitClassType(), -1);

	GET_PLAYER(getOwnerINLINE()).changeExtraUnitCost(-(m_pUnitInfo->getExtraCost()));

	if (m_pUnitInfo->getNukeRange() != -1)
	{
		GET_PLAYER(getOwnerINLINE()).changeNumNukeUnits(-1);
	}

/*************************************************************************************************/
/**	MilSupport (PromotionInfos)		05/15/08										Xienwolf	**/
/**				Prevents Reduction in Military Support Level of Civ on Unit Death				**/
/**								if Promotion still attached										**/
/*************************************************************************************************/
/**								---- Start Original Code ----
	if (m_pUnitInfo->isMilitarySupport())
								----  End Original Code  ----									**/
	if (m_pUnitInfo->isMilitarySupport() && !isNoSupport())
/*************************************************************************************************/
/**	MilSupport (PromotionInfos)					END												**/
/*************************************************************************************************/
	{
		GET_PLAYER(getOwnerINLINE()).changeNumMilitaryUnits(-1);
	}
/*************************************************************************************************/
/**	Upkeep							05/20/08										Xienwolf	**/
/**																								**/
/**					Removes Extra Support Cost from Player upon Unit Death						**/
/*************************************************************************************************/
    GET_PLAYER(getOwnerINLINE()).changeUpkeepCosts(-getExtraSupport());
/*************************************************************************************************/
/**	Upkeep										END												**/
/*************************************************************************************************/


	GET_PLAYER(getOwnerINLINE()).changeAssets(-(m_pUnitInfo->getAssetValue()));

	GET_PLAYER(getOwnerINLINE()).changePower(-(m_pUnitInfo->getPowerValue()));

	GET_PLAYER(getOwnerINLINE()).AI_changeNumAIUnits(AI_getUnitAIType(), -1);

	eOwner = getOwnerINLINE();
	eCapturingPlayer = getCapturingPlayer();

//FfH: Modified by Kael 09/01/2007
//	eCaptureUnitType = ((eCapturingPlayer != NO_PLAYER) ? getCaptureUnitType(GET_PLAYER(eCapturingPlayer).getCivilizationType()) : NO_UNIT);
    eCaptureUnitType = ((eCapturingPlayer != NO_PLAYER) ? getCaptureUnitType(GET_PLAYER(getOwnerINLINE()).getCivilizationType()) : NO_UNIT);
    if (m_pUnitInfo->getUnitCaptureClassType() == getUnitClassType())
    {
        eCaptureUnitType = (UnitTypes)getUnitType();
    }
//FfH: End Modify

	setXY(INVALID_PLOT_COORD, INVALID_PLOT_COORD, true);

	joinGroup(NULL, false, false);

	gDLL->getEventReporterIFace()->unitLost(this);

	GET_PLAYER(getOwnerINLINE()).deleteUnit(getID());

//FfH: Modified by Kael 01/19/2008
//	if ((eCapturingPlayer != NO_PLAYER) && (eCaptureUnitType != NO_UNIT) && !(GET_PLAYER(eCapturingPlayer).isBarbarian()))
	if ((eCapturingPlayer != NO_PLAYER) && (eCaptureUnitType != NO_UNIT))
//FfH: End Modify

	{
		if (GET_PLAYER(eCapturingPlayer).isHuman() || GET_PLAYER(eCapturingPlayer).AI_captureUnit(eCaptureUnitType, pPlot) || 0 == GC.getDefineINT("AI_CAN_DISBAND_UNITS"))
		{
			CvUnit* pkCapturedUnit = GET_PLAYER(eCapturingPlayer).initUnit(eCaptureUnitType, pPlot->getX_INLINE(), pPlot->getY_INLINE());

			if (pkCapturedUnit != NULL)
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_CAPTURED_UNIT", GC.getUnitInfo(eCaptureUnitType).getTextKeyWide());
				gDLL->getInterfaceIFace()->addMessage(eCapturingPlayer, true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_UNITCAPTURE", MESSAGE_TYPE_INFO, pkCapturedUnit->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

				// Add a captured mission
				CvMissionDefinition kMission;
				kMission.setMissionTime(GC.getMissionInfo(MISSION_CAPTURED).getTime() * gDLL->getSecsPerTurn());
				kMission.setUnit(BATTLE_UNIT_ATTACKER, pkCapturedUnit);
				kMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
				kMission.setPlot(pPlot);
				kMission.setMissionType(MISSION_CAPTURED);
				gDLL->getEntityIFace()->AddMission(&kMission);

				pkCapturedUnit->finishMoves();

				if (!GET_PLAYER(eCapturingPlayer).isHuman())
				{
					CvPlot* pPlot = pkCapturedUnit->plot();
					if (pPlot && !pPlot->isCity(false))
					{
						if (GET_PLAYER(eCapturingPlayer).AI_getPlotDanger(pPlot) && GC.getDefineINT("AI_CAN_DISBAND_UNITS")

//FfH: Added by Kael 12/02/2007
                          && pkCapturedUnit->canScrap()
//FfH: End Add

						  )
						{
							pkCapturedUnit->kill(false);
						}
					}
				}
			}
		}
	}
}


void CvUnit::NotifyEntity(MissionTypes eMission)
{
	gDLL->getEntityIFace()->NotifyEntity(getUnitEntity(), eMission);
}


void CvUnit::doTurn()
{
	PROFILE("CvUnit::doTurn()")

	FAssertMsg(!isDead(), "isDead did not return false as expected");
	FAssertMsg(getGroup() != NULL, "getGroup() is not expected to be equal with NULL");

//FfH Spell System: Added by Kael 07/23/2007
    int iI;
    CvPlot* pPlot = plot();
/*************************************************************************************************/
/**	NonAbandon (PromotionInfos)		05/15/08										Xienwolf	**/
/**							Blocks Abandonment Check from Happening								**/
/**						This is called before promotions can Wear off							**/
/*************************************************************************************************/
/**								---- Start Original Code ----
    if (m_pUnitInfo->isAbandon())
								----  End Original Code  ----									**/
    if (m_pUnitInfo->isAbandon() && !(isNonAbandon()))
/*************************************************************************************************/
/**	NonAbandon (PromotionInfos)					END												**/
/*************************************************************************************************/
    {
        bool bValid = true;
		if (m_pUnitInfo->getPrereqCivic() != NO_CIVIC)
		{
            bValid = false;
            for (int iI = 0; iI < GC.getDefineINT("MAX_CIVIC_OPTIONS"); iI++)
            {
                if (GET_PLAYER(getOwnerINLINE()).getCivics((CivicOptionTypes)iI) == m_pUnitInfo->getPrereqCivic())
                {
                    bValid = true;
                }
            }
            if (GET_PLAYER(getOwnerINLINE()).isAnarchy())
            {
                bValid = true;
            }
		}
		if (bValid == true)
		{
            if (m_pUnitInfo->getStateReligion() != NO_RELIGION)
            {
                bValid = false;
                if (GET_PLAYER(getOwnerINLINE()).getStateReligion() == m_pUnitInfo->getStateReligion())
                {
                    bValid = true;
                }
            }
		}
        if (bValid == false)
        {
            gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwnerINLINE(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), gDLL->getText("TXT_KEY_MESSAGE_UNIT_ABANDON", getNameKey()), GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), plot()->getX_INLINE(), plot()->getY_INLINE());
            kill(true);
        }
    }
	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		if (isHasPromotion((PromotionTypes)iI))
		{
		    if (GC.getPromotionInfo((PromotionTypes)iI).getFreeXPPerTurn() != 0)
		    {
                if (getExperience() < GC.getDefineINT("FREE_XP_MAX"))
                {
                    changeExperience(GC.getPromotionInfo((PromotionTypes)iI).getFreeXPPerTurn(), -1, false, false, false);
                }
		    }
		    if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionRandomApply() != NO_PROMOTION)
		    {
                if (GC.getGameINLINE().getSorenRandNum(100, "Promotion Random Apply") <= 50)
                {
                    setHasPromotion(((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionRandomApply()), false);
                }
                else
                {
                    setHasPromotion(((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionRandomApply()), true);
                }
		    }
		    if (GC.getPromotionInfo((PromotionTypes)iI).getBetrayalChance() != 0)
		    {
                if (!isImmuneToCapture() && !isBarbarian() && !GC.getGameINLINE().isOption(GAMEOPTION_NO_BARBARIANS))
                {
                    if (GC.getGameINLINE().getSorenRandNum(100, "Betrayal Chance") <= GC.getPromotionInfo((PromotionTypes)iI).getBetrayalChance())
                    {
                        betray(BARBARIAN_PLAYER);
                    }
                }
		    }
            if (!isEmpty(GC.getPromotionInfo((PromotionTypes)iI).getPyPerTurn()))
            {
                CyUnit* pyUnit = new CyUnit(this);
                CyArgsList argsList;
                argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
                argsList.add(iI);//the promotion #
                gDLL->getPythonIFace()->callFunction(PYSpellModule, "effect", argsList.makeFunctionArgs()); //, &lResult
                delete pyUnit; // python fxn must not hold on to this pointer
            }
		    if (GC.getPromotionInfo((PromotionTypes)iI).getExpireChance() != 0)
		    {
                if (GC.getGameINLINE().getSorenRandNum(100, "Promotion Expire") <= GC.getPromotionInfo((PromotionTypes)iI).getExpireChance())
                {
                    setHasPromotion(((PromotionTypes)iI), false);
                }
		    }
		}
	}
	setHasCasted(false);
    if (getSpellCasterXP() > 0)
    {
        if (GC.getGameINLINE().getSorenRandNum(100, "SpellCasterXP") < getSpellCasterXP() - getExperience())
        {
            changeExperience(1, -1, false, false, false);
        }
    }
	if (getDuration() > 0)
	{
/*************************************************************************************************/
/**	Renewing						05/19/08										Xienwolf	**/
/**																								**/
/**					Includes new variable with natural duration decay							**/
/*************************************************************************************************/
/**								---- Start Original Code ----
	    changeDuration(-1);
	    if (getDuration() == 0)
								----  End Original Code  ----									**/
	    changeDuration(getDurationPerTurn() - 1);
	    if (getDuration() <= 0)
/*************************************************************************************************/
/**	Renewing									END												**/
/*************************************************************************************************/
	    {
            kill(true);
	    }
	}
    if (pPlot->isCity())
    {
        for (iI = 0; iI < GC.getNumBuildingInfos(); iI++)
        {
            if (pPlot->getPlotCity()->getNumBuilding((BuildingTypes)iI) > 0)
            {
                if (GC.getBuildingInfo((BuildingTypes)iI).getRemovePromotion() != NO_PROMOTION)
                {
                    if (isHasPromotion((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getRemovePromotion()))
                    {
                        setHasPromotion((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getRemovePromotion(), false);
                    }
                }
                if (GC.getBuildingInfo((BuildingTypes)iI).isApplyFreePromotionOnMove())
                {
                    if (GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion() != NO_PROMOTION)
					{
//WH: Ploeperpengel begin modify meteoric iron
						if (GC.getPromotionInfo((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion()).getBonusPrereq() != NO_BONUS)
						{
							if (pPlot->getPlotCity()->hasBonus((BonusTypes)GC.getPromotionInfo((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion()).getBonusPrereq()))
							{
								if ((getUnitCombatType() != NO_UNITCOMBAT) && GC.getPromotionInfo((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion()).getUnitCombat(getUnitCombatType()))
								{
									setHasPromotion((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion(), true);
								}
							}
						}
						else if ((getUnitCombatType() != NO_UNITCOMBAT) && GC.getPromotionInfo((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion()).getUnitCombat(getUnitCombatType()))
						{
							setHasPromotion((PromotionTypes)GC.getBuildingInfo((BuildingTypes)iI).getFreePromotion(), true);
						}
//WH: end modify
                    }
                }
            }
        }
        if (m_pUnitInfo->getWeaponTier() > 0)
        {
            setWeapons();
        }
    }
	if (!isHuman())
	{
        int iSpell = chooseSpell();
        if (iSpell != NO_SPELL)
        {
            cast(iSpell);
        }
	}
    if (m_pUnitInfo->isImmortal())
    {
        setImmortal(true);
    }
//FfH: End Add

	testPromotionReady();

	if (isBlockading())
	{
		collectBlockadeGold();
	}

	if (isSpy() && isIntruding() && !isCargo())
	{
		TeamTypes eTeam = plot()->getTeam();
		if (NO_TEAM != eTeam)
		{
			if (GET_TEAM(getTeam()).isOpenBorders(eTeam))
			{
				testSpyIntercepted(plot()->getOwnerINLINE(), GC.getDefineINT("ESPIONAGE_SPY_NO_INTRUDE_INTERCEPT_MOD"));
			}
			else
			{
				testSpyIntercepted(plot()->getOwnerINLINE(), GC.getDefineINT("ESPIONAGE_SPY_INTERCEPT_MOD"));
			}
		}
	}

	if (baseCombatStr() > 0)
	{
		FeatureTypes eFeature = plot()->getFeatureType();
		if (NO_FEATURE != eFeature)
		{
			if (0 != GC.getFeatureInfo(eFeature).getTurnDamage())
			{
				changeDamage(GC.getFeatureInfo(eFeature).getTurnDamage(), NO_PLAYER);
			}
		}
	}

	if (hasMoved())
	{
		if (isAlwaysHeal())
		{
			doHeal();
		}
	}
	else
	{
		if (isHurt())
		{
			doHeal();
		}

		changeFortifyTurns(1);
	}

	changeImmobileTimer(-1);

	setMadeAttack(false);
	setMadeInterception(false);

	setReconPlot(NULL);

	setMoves(0);

//WH: Ploeperpengel add animosity as per ELM 12/08/06
    CyUnit* pyUnit = new CyUnit(this);

    CyArgsList pyArgs;
    pyArgs.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));
    gDLL->getEventReporterIFace()->genericEvent("endUnitTurn", pyArgs.makeFunctionArgs());
//WH: End Add
}


void CvUnit::updateAirStrike(CvPlot* pPlot, bool bQuick, bool bFinish)
{
	bool bVisible = false;

	if (!bFinish)
	{
		if (isFighting())
		{
			return;
		}

		if (!bQuick)
		{
			bVisible = isCombatVisible(NULL);
		}

		if (!airStrike(pPlot))
		{
			return;
		}

		if (bVisible)
		{
			CvAirMissionDefinition kAirMission;
			kAirMission.setMissionType(MISSION_AIRSTRIKE);
			kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
			kAirMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
			kAirMission.setDamage(BATTLE_UNIT_DEFENDER, 0);
			kAirMission.setDamage(BATTLE_UNIT_ATTACKER, 0);
			kAirMission.setPlot(pPlot);
			setCombatTimer(GC.getMissionInfo(MISSION_AIRSTRIKE).getTime());
			GC.getGameINLINE().incrementTurnTimer(getCombatTimer());
			kAirMission.setMissionTime(getCombatTimer() * gDLL->getSecsPerTurn());

			if (pPlot->isActiveVisible(false))
			{
				gDLL->getEntityIFace()->AddMission(&kAirMission);
			}

			return;
		}
	}

	CvUnit *pDefender = getCombatUnit();
	if (pDefender != NULL)
	{
		pDefender->setCombatUnit(NULL);
	}
	setCombatUnit(NULL);
	setAttackPlot(NULL, false);

	getGroup()->clearMissionQueue();

	if (isSuicide() && !isDead())
	{
		kill(true);
	}
}

void CvUnit::resolveAirCombat(CvUnit* pInterceptor, CvPlot* pPlot, CvAirMissionDefinition& kBattle)
{
	CvWString szBuffer;

	int iTheirStrength = (DOMAIN_AIR == pInterceptor->getDomainType() ? pInterceptor->airCurrCombatStr(this) : pInterceptor->currCombatStr(NULL, NULL));
	int iOurStrength = (DOMAIN_AIR == getDomainType() ? airCurrCombatStr(pInterceptor) : currCombatStr(NULL, NULL));
	int iTotalStrength = iOurStrength + iTheirStrength;
	if (0 == iTotalStrength)
	{
		FAssert(false);
		return;
	}

	int iOurOdds = (100 * iOurStrength) / std::max(1, iTotalStrength);

	int iOurRoundDamage = (pInterceptor->currInterceptionProbability() * GC.getDefineINT("MAX_INTERCEPTION_DAMAGE")) / 100;
	int iTheirRoundDamage = (currInterceptionProbability() * GC.getDefineINT("MAX_INTERCEPTION_DAMAGE")) / 100;
	if (getDomainType() == DOMAIN_AIR)
	{
		iTheirRoundDamage = std::max(GC.getDefineINT("MIN_INTERCEPTION_DAMAGE"), iTheirRoundDamage);
	}

	int iTheirDamage = 0;
	int iOurDamage = 0;

	for (int iRound = 0; iRound < GC.getDefineINT("INTERCEPTION_MAX_ROUNDS"); ++iRound)
	{
		if (GC.getGameINLINE().getSorenRandNum(100, "Air combat") < iOurOdds)
		{
			if (DOMAIN_AIR == pInterceptor->getDomainType())
			{
				iTheirDamage += iTheirRoundDamage;
				pInterceptor->changeDamage(iTheirRoundDamage, getOwnerINLINE());
				if (pInterceptor->isDead())
				{
					break;
				}
			}
		}
		else
		{
			iOurDamage += iOurRoundDamage;
			changeDamage(iOurRoundDamage, pInterceptor->getOwnerINLINE());
			if (isDead())
			{
				break;
			}
		}
	}

	if (isDead())
	{
		if (iTheirRoundDamage > 0)
		{
			int iExperience = attackXPValue();
			iExperience = (iExperience * iOurStrength) / std::max(1, iTheirStrength);
			iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
			pInterceptor->changeExperience(iExperience, maxXPValue(), true, pPlot->getOwnerINLINE() == pInterceptor->getOwnerINLINE(), !isBarbarian());
		}
	}
	else if (pInterceptor->isDead())
	{
		int iExperience = pInterceptor->defenseXPValue();
		iExperience = (iExperience * iTheirStrength) / std::max(1, iOurStrength);
		iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
		changeExperience(iExperience, pInterceptor->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pInterceptor->isBarbarian());
	}
	else if (iOurDamage > 0)
	{
		if (iTheirRoundDamage > 0)
		{
			pInterceptor->changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), maxXPValue(), true, pPlot->getOwnerINLINE() == pInterceptor->getOwnerINLINE(), !isBarbarian());
		}
	}
	else if (iTheirDamage > 0)
	{
		changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pInterceptor->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pInterceptor->isBarbarian());
	}

	kBattle.setDamage(BATTLE_UNIT_ATTACKER, iOurDamage);
	kBattle.setDamage(BATTLE_UNIT_DEFENDER, iTheirDamage);
}


void CvUnit::updateAirCombat(bool bQuick)
{
	CvUnit* pInterceptor = NULL;
	bool bFinish = false;

	FAssert(getDomainType() == DOMAIN_AIR || getDropRange() > 0);

	if (getCombatTimer() > 0)
	{
		changeCombatTimer(-1);

		if (getCombatTimer() > 0)
		{
			return;
		}
		else
		{
			bFinish = true;
		}
	}

	CvPlot* pPlot = getAttackPlot();
	if (pPlot == NULL)
	{
		return;
	}

	if (bFinish)
	{
		pInterceptor = getCombatUnit();
	}
	else
	{
		pInterceptor = bestInterceptor(pPlot);
	}


	if (pInterceptor == NULL)
	{
		setAttackPlot(NULL, false);
		setCombatUnit(NULL);

		getGroup()->clearMissionQueue();

		return;
	}

	//check if quick combat
	bool bVisible = false;
	if (!bQuick)
	{
		bVisible = isCombatVisible(pInterceptor);
	}

	//if not finished and not fighting yet, set up combat damage and mission
	if (!bFinish)
	{
		if (!isFighting())
		{
			if (plot()->isFighting() || pPlot->isFighting())
			{
				return;
			}

			setMadeAttack(true);

			setCombatUnit(pInterceptor, true);
			pInterceptor->setCombatUnit(this, false);
		}

		FAssertMsg(pInterceptor != NULL, "Defender is not assigned a valid value");

		FAssertMsg(plot()->isFighting(), "Current unit instance plot is not fighting as expected");
		FAssertMsg(pInterceptor->plot()->isFighting(), "pPlot is not fighting as expected");

		CvAirMissionDefinition kAirMission;
		if (DOMAIN_AIR != getDomainType())
		{
			kAirMission.setMissionType(MISSION_PARADROP);
		}
		else
		{
			kAirMission.setMissionType(MISSION_AIRSTRIKE);
		}
		kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
		kAirMission.setUnit(BATTLE_UNIT_DEFENDER, pInterceptor);

		resolveAirCombat(pInterceptor, pPlot, kAirMission);

		if (!bVisible)
		{
			bFinish = true;
		}
		else
		{
			kAirMission.setPlot(pPlot);
			kAirMission.setMissionTime(GC.getMissionInfo(MISSION_AIRSTRIKE).getTime() * gDLL->getSecsPerTurn());
			setCombatTimer(GC.getMissionInfo(MISSION_AIRSTRIKE).getTime());
			GC.getGameINLINE().incrementTurnTimer(getCombatTimer());

			if (pPlot->isActiveVisible(false))
			{
				gDLL->getEntityIFace()->AddMission(&kAirMission);
			}
		}

		changeMoves(GC.getMOVE_DENOMINATOR());
		if (DOMAIN_AIR != pInterceptor->getDomainType())
		{
			pInterceptor->setMadeInterception(true);
		}

		if (isDead())
		{
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SHOT_DOWN_ENEMY", pInterceptor->getNameKey(), getNameKey(), getVisualCivAdjective(pInterceptor->getTeam()));
			gDLL->getInterfaceIFace()->addMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_SHOT_DOWN", getNameKey(), pInterceptor->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

/*************************************************************************************************/
/**	Food from Animals				01/04/08			Written: DomPedroII	Imported: Xienwolf	**/
/**																								**/
/**						Salvage Function for Aerial Defense Victory								**/
/*************************************************************************************************/
            if (pPlot->getOwnerINLINE() == pInterceptor->getOwnerINLINE())
            {
                pInterceptor->salvage(this);
            }
/*************************************************************************************************/
/**	Food from Animals							END												**/
/*************************************************************************************************/

		}
		else if (kAirMission.getDamage(BATTLE_UNIT_ATTACKER) > 0)
		{
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_HURT_ENEMY_AIR", pInterceptor->getNameKey(), getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_ATTACKER)), getVisualCivAdjective(pInterceptor->getTeam()));
			gDLL->getInterfaceIFace()->addMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_AIR_UNIT_HURT", getNameKey(), pInterceptor->getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_ATTACKER)));
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
		}

		if (pInterceptor->isDead())
		{
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SHOT_DOWN_ENEMY", getNameKey(), pInterceptor->getNameKey(), pInterceptor->getVisualCivAdjective(getTeam()));
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_SHOT_DOWN", pInterceptor->getNameKey(), getNameKey());
			gDLL->getInterfaceIFace()->addMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
		}
		else if (kAirMission.getDamage(BATTLE_UNIT_DEFENDER) > 0)
		{
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_DAMAGED_ENEMY_AIR", getNameKey(), pInterceptor->getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_DEFENDER)), pInterceptor->getVisualCivAdjective(getTeam()));
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_AIR_UNIT_DAMAGED", pInterceptor->getNameKey(), getNameKey(), -(kAirMission.getDamage(BATTLE_UNIT_DEFENDER)));
			gDLL->getInterfaceIFace()->addMessage(pInterceptor->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
		}

		if (0 == kAirMission.getDamage(BATTLE_UNIT_ATTACKER) + kAirMission.getDamage(BATTLE_UNIT_DEFENDER))
		{
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ABORTED_ENEMY_AIR", pInterceptor->getNameKey(), getNameKey(), getVisualCivAdjective(getTeam()));
			gDLL->getInterfaceIFace()->addMessage(pInterceptor->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPT", MESSAGE_TYPE_INFO, pInterceptor->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_AIR_UNIT_ABORTED", getNameKey(), pInterceptor->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_INTERCEPTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
		}
	}

	if (bFinish)
	{
		setAttackPlot(NULL, false);
		setCombatUnit(NULL);
		pInterceptor->setCombatUnit(NULL);

		if (!isDead() && isSuicide())
		{
			kill(true);
		}
	}
}

void CvUnit::resolveCombat(CvUnit* pDefender, CvPlot* pPlot, CvBattleDefinition& kBattle)
{
	CombatDetails cdAttackerDetails;
	CombatDetails cdDefenderDetails;

	int iAttackerStrength = currCombatStr(NULL, NULL, &cdAttackerDetails);
	int iAttackerFirepower = currFirepower(NULL, NULL);
	int iDefenderStrength;
	int iAttackerDamage;
	int iDefenderDamage;
	int iDefenderOdds;

	getDefenderCombatValues(*pDefender, pPlot, iAttackerStrength, iAttackerFirepower, iDefenderOdds, iDefenderStrength, iAttackerDamage, iDefenderDamage, &cdDefenderDetails);

	if (isHuman() || pDefender->isHuman())
	{
		//Added ST
		CyArgsList pyArgsCD;
		pyArgsCD.add(gDLL->getPythonIFace()->makePythonObject(&cdAttackerDetails));
		pyArgsCD.add(gDLL->getPythonIFace()->makePythonObject(&cdDefenderDetails));
		pyArgsCD.add(getCombatOdds(this, pDefender));
		gDLL->getEventReporterIFace()->genericEvent("combatLogCalc", pyArgsCD.makeFunctionArgs());
	}

	collateralCombat(pPlot, pDefender);

	while (true)
	{
		if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Combat") < iDefenderOdds)
		{
			if (getCombatFirstStrikes() == 0)
			{
				if (getDamage() + iAttackerDamage >= maxHitPoints() && GC.getGameINLINE().getSorenRandNum(100, "Withdrawal") < withdrawalProbability())
				{
					flankingStrikeCombat(pPlot, iAttackerStrength, iAttackerFirepower, pDefender);

					changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pDefender->isBarbarian());

//FfH Promotions: Added by Kael 08/12/2007
                    setFleeWithdrawl(true);
//FfH: End Add

					break;
				}

//FfH Promotions: Added by Kael 08/12/2007
                if (getDamage() + iAttackerDamage >= maxHitPoints() && isImmortal())
                {
                    setFleeImmortal(true);
                    break;
                }
//FfH: End Add

				changeDamage(iAttackerDamage, pDefender->getOwnerINLINE());

				if (pDefender->getCombatFirstStrikes() > 0 && pDefender->isRanged())
				{
					kBattle.addFirstStrikes(BATTLE_UNIT_DEFENDER, 1);
					kBattle.addDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, iAttackerDamage);
				}

				cdAttackerDetails.iCurrHitPoints = currHitPoints();

				if (isHuman() || pDefender->isHuman())
				{
					CyArgsList pyArgs;
					pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdAttackerDetails));
					pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdDefenderDetails));
					pyArgs.add(1);
					pyArgs.add(iAttackerDamage);
					gDLL->getEventReporterIFace()->genericEvent("combatLogHit", pyArgs.makeFunctionArgs());
				}
			}
		}
		else
		{
			if (pDefender->getCombatFirstStrikes() == 0)
			{

//FfH Promotions: Added by Kael 08/12/2007
                if (pDefender->getDamage() + iDefenderDamage >= pDefender->maxHitPoints() && pDefender->isImmortal())
                {
                    pDefender->setFleeImmortal(true);
                    break;
                }
                if (pDefender->getDamage() + iDefenderDamage >= pDefender->maxHitPoints())
                {
                    if (!pPlot->isCity())
                    {
                        if (GC.getGameINLINE().getSorenRandNum(100, "Withdrawal") < pDefender->getWithdrawlProbDefensive())
                        {
                            pDefender->setFleeWithdrawl(true);
                            break;
                        }
                    }
                }
//FfH: End Add

				if (std::min(GC.getMAX_HIT_POINTS(), pDefender->getDamage() + iDefenderDamage) > combatLimit())
				{
					changeExperience(GC.getDefineINT("EXPERIENCE_FROM_WITHDRAWL"), pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pDefender->isBarbarian());
					pDefender->setDamage(combatLimit(), getOwnerINLINE());

//FfH: Added by Kael 05/27/2008
                    setMadeAttack(true);
                    changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
//FfH: End Add

					break;
				}

				pDefender->changeDamage(iDefenderDamage, getOwnerINLINE());

				if (getCombatFirstStrikes() > 0 && isRanged())
				{
					kBattle.addFirstStrikes(BATTLE_UNIT_ATTACKER, 1);
					kBattle.addDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, iDefenderDamage);
				}

				cdDefenderDetails.iCurrHitPoints=pDefender->currHitPoints();

				if (isHuman() || pDefender->isHuman())
				{
					CyArgsList pyArgs;
					pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdAttackerDetails));
					pyArgs.add(gDLL->getPythonIFace()->makePythonObject(&cdDefenderDetails));
					pyArgs.add(0);
					pyArgs.add(iDefenderDamage);
					gDLL->getEventReporterIFace()->genericEvent("combatLogHit", pyArgs.makeFunctionArgs());
				}
			}
		}

		if (getCombatFirstStrikes() > 0)
		{
			changeCombatFirstStrikes(-1);
		}

		if (pDefender->getCombatFirstStrikes() > 0)
		{
			pDefender->changeCombatFirstStrikes(-1);
		}

		if (isDead() || pDefender->isDead())
		{
			if (isDead())
			{
				int iExperience = defenseXPValue();
				iExperience = ((iExperience * iAttackerStrength) / iDefenderStrength);
				iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
				pDefender->changeExperience(iExperience, maxXPValue(), true, pPlot->getOwnerINLINE() == pDefender->getOwnerINLINE(), !isBarbarian());
			}
			else
			{
				flankingStrikeCombat(pPlot, iAttackerStrength, iAttackerFirepower, pDefender);

				int iExperience = pDefender->attackXPValue();
				iExperience = ((iExperience * iDefenderStrength) / iAttackerStrength);
				iExperience = range(iExperience, GC.getDefineINT("MIN_EXPERIENCE_PER_COMBAT"), GC.getDefineINT("MAX_EXPERIENCE_PER_COMBAT"));
				changeExperience(iExperience, pDefender->maxXPValue(), true, pPlot->getOwnerINLINE() == getOwnerINLINE(), !pDefender->isBarbarian());
			}

			break;
		}
	}
}


//WH: Ploeperpengel Add Animosity as per Elm 12/08/06
//void CvUnit::updateCombat(bool bQuick)
void CvUnit::updateCombat(bool bQuick, bool bAnimosity, CvUnit* pTargetUnit)
//WH: end Add
{
	CvWString szBuffer;

	bool bFinish = false;
	bool bVisible = false;

	if (getCombatTimer() > 0)
	{
		changeCombatTimer(-1);

		if (getCombatTimer() > 0)
		{
			return;
		}
		else
		{
			bFinish = true;
		}
	}

	CvPlot* pPlot = getAttackPlot();

	if (pPlot == NULL)
	{
		return;
	}

	if (getDomainType() == DOMAIN_AIR)
	{
		updateAirStrike(pPlot, bQuick, bFinish);
		return;
	}

	CvUnit* pDefender = NULL;
	if (bFinish)
	{
		pDefender = getCombatUnit();
	}
	else
	{
//WH: Ploeperpengel Add Animosity as per Elm 12/08/06
//		pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
	//Allow a friendly unit to be a defender
		if (bAnimosity)
		{
		    pDefender = pTargetUnit;
        }
        else
        {
            pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
        }
//WH: end Add
	}
	if (pDefender == NULL)
	{
		setAttackPlot(NULL, false);
		setCombatUnit(NULL);

		getGroup()->groupMove(pPlot, true, ((canAdvance(pPlot, 0)) ? this : NULL));

		getGroup()->clearMissionQueue();

		return;
	}

	//check if quick combat
	if (!bQuick)
	{
		bVisible = isCombatVisible(pDefender);
	}

	//FAssertMsg((pPlot == pDefender->plot()), "There is not expected to be a defender or the defender's plot is expected to be pPlot (the attack plot)");

//FfH Fear: Added by Kael 07/30/2007
    if (pDefender->isFear())
    {
        if (!isImmuneToFear())
        {
            if (GC.getGameINLINE().getSorenRandNum(20, "Im afeared!") > (baseCombatStr() + 5 - pDefender->baseCombatStr()))
            {
                setMadeAttack(true);
                changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
                szBuffer = gDLL->getText("TXT_KEY_MESSAGE_IM_AFEARED", getNameKey());
                gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)getOwner()), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, "Art/Interface/Buttons/Promotions/Fear.dds", (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                bFinish = true;
            }
        }
    }
//FfH: End Add

	//if not finished and not fighting yet, set up combat damage and mission
	if (!bFinish)
	{
		if (!isFighting())
		{
			if (plot()->isFighting() || pPlot->isFighting())
			{
				return;
			}

			setMadeAttack(true);

			//rotate to face plot
			DirectionTypes newDirection = estimateDirection(this->plot(), pDefender->plot());
			if (newDirection != NO_DIRECTION)
			{
				setFacingDirection(newDirection);
			}

			//rotate enemy to face us
			newDirection = estimateDirection(pDefender->plot(), this->plot());
			if (newDirection != NO_DIRECTION)
			{
				pDefender->setFacingDirection(newDirection);
			}

			setCombatUnit(pDefender, true);
			pDefender->setCombatUnit(this, false);

			pDefender->getGroup()->clearMissionQueue();

			bool bFocused = (bVisible && isCombatFocus() && gDLL->getInterfaceIFace()->isCombatFocus());

			if (bFocused)
			{
				DirectionTypes directionType = directionXY(plot(), pPlot);
				//								N			NE				E				SE					S				SW					W				NW
				NiPoint2 directions[8] = {NiPoint2(0, 1), NiPoint2(1, 1), NiPoint2(1, 0), NiPoint2(1, -1), NiPoint2(0, -1), NiPoint2(-1, -1), NiPoint2(-1, 0), NiPoint2(-1, 1)};
				NiPoint3 attackDirection = NiPoint3(directions[directionType].x, directions[directionType].y, 0);
				float plotSize = GC.getPLOT_SIZE();
				NiPoint3 lookAtPoint(plot()->getPoint().x + plotSize / 2 * attackDirection.x, plot()->getPoint().y + plotSize / 2 * attackDirection.y, (plot()->getPoint().z + pPlot->getPoint().z) / 2);
				attackDirection.Unitize();
				gDLL->getInterfaceIFace()->lookAt(lookAtPoint, (((getOwnerINLINE() != GC.getGameINLINE().getActivePlayer()) || gDLL->getGraphicOption(GRAPHICOPTION_NO_COMBAT_ZOOM)) ? CAMERALOOKAT_BATTLE : CAMERALOOKAT_BATTLE_ZOOM_IN), attackDirection);
			}
			else
			{
				PlayerTypes eAttacker = getVisualOwner(pDefender->getTeam());
				CvWString szMessage;
				if (BARBARIAN_PLAYER != eAttacker)
				{
					szMessage = gDLL->getText("TXT_KEY_MISC_YOU_UNITS_UNDER_ATTACK", GET_PLAYER(getOwnerINLINE()).getNameKey());
				}
				else
				{
					szMessage = gDLL->getText("TXT_KEY_MISC_YOU_UNITS_UNDER_ATTACK_UNKNOWN");
				}

				gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szMessage, "AS2D_COMBAT", MESSAGE_TYPE_DISPLAY_ONLY, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true);
			}
		}

		FAssertMsg(pDefender != NULL, "Defender is not assigned a valid value");

		FAssertMsg(plot()->isFighting(), "Current unit instance plot is not fighting as expected");
		FAssertMsg(pPlot->isFighting(), "pPlot is not fighting as expected");

		if (!pDefender->canDefend())
		{
			if (!bVisible)
			{
				bFinish = true;
			}
			else
			{
				CvMissionDefinition kMission;
				kMission.setMissionTime(getCombatTimer() * gDLL->getSecsPerTurn());
				kMission.setMissionType(MISSION_SURRENDER);
				kMission.setUnit(BATTLE_UNIT_ATTACKER, this);
				kMission.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
				kMission.setPlot(pPlot);
				gDLL->getEntityIFace()->AddMission(&kMission);

				// Surrender mission
				setCombatTimer(GC.getMissionInfo(MISSION_SURRENDER).getTime());

				GC.getGameINLINE().incrementTurnTimer(getCombatTimer());
			}

			// Kill them!
			pDefender->setDamage(GC.getMAX_HIT_POINTS());
		}
		else
		{
			CvBattleDefinition kBattle;
			kBattle.setUnit(BATTLE_UNIT_ATTACKER, this);
			kBattle.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
			kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_BEGIN, getDamage());
			kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_BEGIN, pDefender->getDamage());

			resolveCombat(pDefender, pPlot, kBattle);

			if (!bVisible)
			{
				bFinish = true;
			}
			else
			{
				kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_END, getDamage());
				kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_END, pDefender->getDamage());
				kBattle.setAdvanceSquare(canAdvance(pPlot, 1));

				if (isRanged() && pDefender->isRanged())
				{
					kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_END));
					kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_END));
				}
				else
				{
					kBattle.addDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_BEGIN));
					kBattle.addDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_BEGIN));
				}

				int iTurns = planBattle( kBattle);
				kBattle.setMissionTime(iTurns * gDLL->getSecsPerTurn());
				setCombatTimer(iTurns);

				GC.getGameINLINE().incrementTurnTimer(getCombatTimer());

				if (pPlot->isActiveVisible(false))
				{
					ExecuteMove(0.5f, true);
					gDLL->getEntityIFace()->AddMission(&kBattle);
				}
			}
		}
	}

	if (bFinish)
	{
		if (bVisible)
		{
			if (isCombatFocus() && gDLL->getInterfaceIFace()->isCombatFocus())
			{
				if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
				{
					gDLL->getInterfaceIFace()->releaseLockedCamera();
				}
			}
		}

		//end the combat mission if this code executes first
		gDLL->getEntityIFace()->RemoveUnitFromBattle(this);
		gDLL->getEntityIFace()->RemoveUnitFromBattle(pDefender);
		setAttackPlot(NULL, false);
		setCombatUnit(NULL);
		pDefender->setCombatUnit(NULL);
		NotifyEntity(MISSION_DAMAGE);
		pDefender->NotifyEntity(MISSION_DAMAGE);

		if (isDead())
		{
			if (isBarbarian())
			{
				GET_PLAYER(pDefender->getOwnerINLINE()).changeWinsVsBarbs(1);
			}

/*************************************************************************************************/
/**	Food from Animals				01/04/08			Written: DomPedroII	Imported: Xienwolf	**/
/**																								**/
/**					Initiates Salvaging Effect after Defensive Victory							**/
/*************************************************************************************************/
            if (!pDefender->isBarbarian())
            {
                pDefender->salvage(this);
            }
/*************************************************************************************************/
/**	Food from Animals							END												**/
/*************************************************************************************************/


//FfH Hidden Nationality: Modified by Kael 08/27/2007
//			if (!m_pUnitInfo->isHiddenNationality() && !pDefender->getUnitInfo().isHiddenNationality())
/*************************************************************************************************/
/**	NoWeary (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**						Stops Weariness Check if Attacker is Flagged & Killed					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
			if (!isHiddenNationality() && !pDefender->isHiddenNationality() && getDuration() == 0 && !m_pUnitInfo->isNoWarWeariness())
								----  End Original Code  ----									**/
			if (!isHiddenNationality() && !pDefender->isHiddenNationality() && getDuration() == 0 && !m_pUnitInfo->isNoWarWeariness() && !(isNonWarWeariness()))
/*************************************************************************************************/
/**	NoWeary (PromotionInfos)					END												**/
/*************************************************************************************************/
//FfH: End Modify

			{
				GET_TEAM(getTeam()).changeWarWeariness(pDefender->getTeam(), *pPlot, GC.getDefineINT("WW_UNIT_KILLED_ATTACKING"));
				GET_TEAM(pDefender->getTeam()).changeWarWeariness(getTeam(), *pPlot, GC.getDefineINT("WW_KILLED_UNIT_DEFENDING"));
				GET_TEAM(pDefender->getTeam()).AI_changeWarSuccess(getTeam(), GC.getDefineINT("WAR_SUCCESS_DEFENDING"));
			}

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_DIED_ATTACKING", getNameKey(), pDefender->getNameKey());

//WH: added by Ploeperpengel 04/23/2008--- BEGIN InfluenceDrivenWar ---by Moctezuma----
			float fInfluenceRatio = 0.0;
			if (GC.getDefineINT("IDW_ENABLED"))
			{
				fInfluenceRatio = pDefender->doVictoryInfluence(this, false, false);
				CvWString szTempBuffer;
				szTempBuffer.Format(L" Influence: -%.1f%%", fInfluenceRatio);
				szBuffer += szTempBuffer;
			}
// ------ END InfluenceDrivenWar ---------------------------------

			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_KILLED_ENEMY_UNIT", pDefender->getNameKey(), getNameKey(), getVisualCivAdjective(pDefender->getTeam()));

//WH: added by Ploeperpengel 04/23/2008--- BEGIN InfluenceDrivenWar ---by Moctezuma----
			if (GC.getDefineINT("IDW_ENABLED"))
			{
				CvWString szTempBuffer;
				szTempBuffer.Format(L" Influence: +%.1f%%", fInfluenceRatio);
				szBuffer += szTempBuffer;
			}
// ------ END InfluenceDrivenWar ---------------------------------

			gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

//FfH: Added by Kael 07/30/2007
            pDefender->combatWon(this, false);
//FfH: End Add

			// report event to Python, along with some other key state
			gDLL->getEventReporterIFace()->combatResult(pDefender, this);
		}
		else if (pDefender->isDead())
		{
			if (pDefender->isBarbarian())
			{
				GET_PLAYER(getOwnerINLINE()).changeWinsVsBarbs(1);
			}

/*************************************************************************************************/
/**	Food from Animals				01/04/08			Written: DomPedroII	Imported: Xienwolf	**/
/**																								**/
/**					Initiates Salvaging Effect after Offensive Victory							**/
/*************************************************************************************************/
            if (!isBarbarian())
            {
                salvage(pDefender);
            }
/*************************************************************************************************/
/**	Food from Animals							END												**/
/*************************************************************************************************/

//FfH Hidden Nationality: Modified by Kael 08/27/2007
//			if (!m_pUnitInfo->isHiddenNationality() && !pDefender->getUnitInfo().isHiddenNationality())
/*************************************************************************************************/
/**	NoWeary (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**						Stops Weariness Check if Defender is Flagged & Killed					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
			if (!isHiddenNationality() && !pDefender->isHiddenNationality() && pDefender->getDuration() == 0 && !pDefender->getUnitInfo().isNoWarWeariness())
								----  End Original Code  ----									**/
			if (!isHiddenNationality() && !pDefender->isHiddenNationality() && pDefender->getDuration() == 0 && !pDefender->getUnitInfo().isNoWarWeariness() && !(isNonWarWeariness()))
/*************************************************************************************************/
/**	NoWeary (PromotionInfos)					END												**/
/*************************************************************************************************/
//FfH: End Modify

			{
				GET_TEAM(pDefender->getTeam()).changeWarWeariness(getTeam(), *pPlot, GC.getDefineINT("WW_UNIT_KILLED_DEFENDING"));
				GET_TEAM(getTeam()).changeWarWeariness(pDefender->getTeam(), *pPlot, GC.getDefineINT("WW_KILLED_UNIT_ATTACKING"));
				GET_TEAM(getTeam()).AI_changeWarSuccess(pDefender->getTeam(), GC.getDefineINT("WAR_SUCCESS_ATTACKING"));
			}

			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_DESTROYED_ENEMY", getNameKey(), pDefender->getNameKey());

//WH: added by Ploeperpengel 04/23/2008--- BEGIN InfluenceDrivenWar ---by Moctezuma----
			float fInfluenceRatio = 0.0;			
			if (GC.getDefineINT("IDW_ENABLED"))
			{
				fInfluenceRatio = doVictoryInfluence(pDefender, true, false);
				CvWString szTempBuffer;
				szTempBuffer.Format(L" Influence: +%.1f%%", fInfluenceRatio);
				szBuffer += szTempBuffer;
			}
// ------ END InfluenceDrivenWar ---------------------------------

			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
			if (getVisualOwner(pDefender->getTeam()) != getOwnerINLINE())
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WAS_DESTROYED_UNKNOWN", pDefender->getNameKey(), getNameKey());
			}
			else
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WAS_DESTROYED", pDefender->getNameKey(), getNameKey(), getVisualCivAdjective(pDefender->getTeam()));
			}

//WH: added by Ploeperpengel 04/23/2008--- BEGIN InfluenceDrivenWar ---by Moctezuma----
			if (GC.getDefineINT("IDW_ENABLED"))
			{
				CvWString szTempBuffer;
				szTempBuffer.Format(L" Influence: -%.1f%%", fInfluenceRatio);
				szBuffer += szTempBuffer;
			}
// ------ END InfluenceDrivenWar ---------------------------------

			gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer,GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

//FfH: Added by Kael 05/15/2007
            combatWon(pDefender, true);
//FfH: End Add

			// report event to Python, along with some other key state
			gDLL->getEventReporterIFace()->combatResult(this, pDefender);

			bool bAdvance = false;

			if (isSuicide())
			{
				kill(true);

				pDefender->kill(false);
				pDefender = NULL;
			}
			else
			{
				bAdvance = canAdvance(pPlot, ((pDefender->canDefend()) ? 1 : 0));

				if (bAdvance)
				{
					if (!isNoCapture()

//FfH: Added by Kael 11/14/2007
					 || GC.getUnitInfo((UnitTypes)pDefender->getUnitType()).getEquipmentPromotion() != NO_PROMOTION
//FfH: End Add

					 )
					{
						pDefender->setCapturingPlayer(getOwnerINLINE());
					}
				}


				pDefender->kill(false);
				pDefender = NULL;

//FfH Fear: Added by Kael 07/30/2007
                if (isFear() && pPlot->isCity() == false)
                {
                    CvUnit* pLoopUnit;
                    CLLNode<IDInfo>* pUnitNode;
                    pUnitNode = pPlot->headUnitNode();
                    while (pUnitNode != NULL)
                    {
                        pLoopUnit = ::getUnit(pUnitNode->m_data);
                        pUnitNode = pPlot->nextUnitNode(pUnitNode);
                        if (pLoopUnit->isEnemy(getTeam()))
                        {
                            if (!pLoopUnit->isImmuneToFear())
                            {
                                if (GC.getGameINLINE().getSorenRandNum(20, "Im afeared!") <= (baseCombatStr() + 10 - pLoopUnit->baseCombatStr()))
                                {
                                    pLoopUnit->joinGroup(NULL);
                                    pLoopUnit->jumpToNearestValidPlot();
                                }
                            }
                        }
                    }
                }
                bAdvance = canAdvance(pPlot, 0);
//FfH: End Add

				if (!bAdvance)
				{
					changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));

					if (!canMove() || !isBlitz())
					{
						if (IsSelected())
						{
							if (gDLL->getInterfaceIFace()->getLengthSelectionList() > 1)
							{
								gDLL->getInterfaceIFace()->removeFromSelectionList(this);
							}
						}
					}
				}
			}

			if (pPlot->getNumVisibleEnemyDefenders(this) == 0)
			{
				getGroup()->groupMove(pPlot, true, ((bAdvance) ? this : NULL));
			}

			// This is is put before the plot advancement, the unit will always try to walk back
			// to the square that they came from, before advancing.
			getGroup()->clearMissionQueue();
		}
		else
		{

//FfH Promotions: Modified by Kael 08/12/2007
//			szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WITHDRAW", getNameKey(), pDefender->getNameKey());
//			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_OUR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
//			szBuffer = gDLL->getText("TXT_KEY_MISC_ENEMY_UNIT_WITHDRAW", getNameKey(), pDefender->getNameKey());
//			gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_THEIR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
//
//			changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
//
//			getGroup()->clearMissionQueue();
            if (isFleeImmortal())
            {
                joinGroup(NULL);
                setFleeImmortal(false);
                doImmortalRebirth();
            }
            if (pDefender->isFleeImmortal())
            {
                pDefender->joinGroup(NULL);
                pDefender->setFleeImmortal(false);
                pDefender->doImmortalRebirth();
                changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
                getGroup()->groupMove(pPlot, true, ((canAdvance(pPlot, 0)) ? this : NULL));
                getGroup()->clearMissionQueue();
            }
            if (pDefender->isFleeWithdrawl())
            {
                pDefender->joinGroup(NULL);
                pDefender->setFleeWithdrawl(false);
                pDefender->jumpToNearestValidPlot();
                changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));
                getGroup()->groupMove(pPlot, true, ((canAdvance(pPlot, 0)) ? this : NULL));
                getGroup()->clearMissionQueue();
                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_FLED", pDefender->getNameKey(), getNameKey());
                gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_OUR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                szBuffer = gDLL->getText("TXT_KEY_MISC_ENEMY_UNIT_FLED", pDefender->getNameKey(), getNameKey());
                gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_THEIR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
            }
            if (isFleeWithdrawl())
            {
                joinGroup(NULL);
                setFleeWithdrawl(false);
                szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_WITHDRAW", getNameKey(), pDefender->getNameKey());
                gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_OUR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                szBuffer = gDLL->getText("TXT_KEY_MISC_ENEMY_UNIT_WITHDRAW", getNameKey(), pDefender->getNameKey());
                gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_THEIR_WITHDRAWL", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
                changeMoves(std::max(GC.getMOVE_DENOMINATOR(), pPlot->movementCost(this, plot())));

//WH: added by Ploeperpengel 04/23/2008 ------ BEGIN InfluenceDrivenWar ---by Moctezuma--------
				if (!canMove() || !isBlitz())
				{
					if (IsSelected())
					{
						if (gDLL->getInterfaceIFace()->getLengthSelectionList() > 1)
						{
							gDLL->getInterfaceIFace()->removeFromSelectionList(this);
						}
					}
				}
// ------ END InfluenceDrivenWar -------------------------------

				getGroup()->clearMissionQueue();
            }
//FfH: End Modify

		}
	}
}


bool CvUnit::isActionRecommended(int iAction)
{
	CvCity* pWorkingCity;
	CvPlot* pPlot;
	ImprovementTypes eImprovement;
	ImprovementTypes eFinalImprovement;
	BuildTypes eBuild;
	RouteTypes eRoute;
	BonusTypes eBonus;
	int iIndex;

	if (getOwnerINLINE() != GC.getGameINLINE().getActivePlayer())
	{
		return false;
	}

	if (GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_NO_UNIT_RECOMMENDATIONS))
	{
		return false;
	}

	CyUnit* pyUnit = new CyUnit(this);
	CyArgsList argsList;
	argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
	argsList.add(iAction);
	long lResult=0;
	gDLL->getPythonIFace()->callFunction(PYGameModule, "isActionRecommended", argsList.makeFunctionArgs(), &lResult);
	delete pyUnit;	// python fxn must not hold on to this pointer
	if (lResult == 1)
	{
		return true;
	}

	pPlot = gDLL->getInterfaceIFace()->getGotoPlot();

	if (pPlot == NULL)
	{
		if (gDLL->shiftKey())
		{
			pPlot = getGroup()->lastMissionPlot();
		}
	}

	if (pPlot == NULL)
	{
		pPlot = plot();
	}

	if (GC.getActionInfo(iAction).getMissionType() == MISSION_FORTIFY)
	{
		if (pPlot->isCity(true, getTeam()))
		{
			if (canDefend(pPlot))
			{
				if (pPlot->getNumDefenders(getOwnerINLINE()) < ((atPlot(pPlot)) ? 2 : 1))
				{
					return true;
				}
			}
		}
	}

	if (GC.getActionInfo(iAction).getMissionType() == MISSION_HEAL)
	{
		if (isHurt())
		{
			if (!hasMoved())
			{
				if ((pPlot->getTeam() == getTeam()) || (healTurns(pPlot) < 4))
				{
					return true;
				}
			}
		}
	}

	if (GC.getActionInfo(iAction).getMissionType() == MISSION_FOUND)
	{
		if (canFound(pPlot))
		{
			if (pPlot->isBestAdjacentFound(getOwnerINLINE()))
			{
				return true;
			}
		}
	}

	if (GC.getActionInfo(iAction).getMissionType() == MISSION_BUILD)
	{
		if (pPlot->getOwner() == getOwnerINLINE())
		{
			eBuild = ((BuildTypes)(GC.getActionInfo(iAction).getMissionData()));
			FAssert(eBuild != NO_BUILD);
			FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");

			if (canBuild(pPlot, eBuild))
			{
				eImprovement = ((ImprovementTypes)(GC.getBuildInfo(eBuild).getImprovement()));
				eRoute = ((RouteTypes)(GC.getBuildInfo(eBuild).getRoute()));
				eBonus = pPlot->getBonusType(getTeam());
				pWorkingCity = pPlot->getWorkingCity();

				if (pPlot->getImprovementType() == NO_IMPROVEMENT)
				{
					if (pWorkingCity != NULL)
					{
						iIndex = pWorkingCity->getCityPlotIndex(pPlot);

						if (iIndex != -1)
						{
							if (pWorkingCity->AI_getBestBuild(iIndex) == eBuild)
							{
								return true;
							}
						}
					}

					if (eImprovement != NO_IMPROVEMENT)
					{
						if (eBonus != NO_BONUS)
						{
							if (GC.getImprovementInfo(eImprovement).isImprovementBonusTrade(eBonus))
							{
								return true;
							}
						}

						if (pPlot->getImprovementType() == NO_IMPROVEMENT)
						{
							if (!(pPlot->isIrrigated()) && pPlot->isIrrigationAvailable(true))
							{
								if (GC.getImprovementInfo(eImprovement).isCarriesIrrigation())
								{
									return true;
								}
							}

							if (pWorkingCity != NULL)
							{
								if (GC.getImprovementInfo(eImprovement).getYieldChange(YIELD_FOOD) > 0)
								{
									return true;
								}

								if (pPlot->isHills())
								{
									if (GC.getImprovementInfo(eImprovement).getYieldChange(YIELD_PRODUCTION) > 0)
									{
										return true;
									}
								}
								else
								{
									if (GC.getImprovementInfo(eImprovement).getYieldChange(YIELD_COMMERCE) > 0)
									{
										return true;
									}
								}
							}
						}
					}
				}

				if (eRoute != NO_ROUTE)
				{
					if (!(pPlot->isRoute()))
					{
						if (eBonus != NO_BONUS)
						{
							return true;
						}

						if (pWorkingCity != NULL)
						{
							if (pPlot->isRiver())
							{
								return true;
							}
						}
					}

					eFinalImprovement = eImprovement;

					if (eFinalImprovement == NO_IMPROVEMENT)
					{
						eFinalImprovement = pPlot->getImprovementType();
					}

					if (eFinalImprovement != NO_IMPROVEMENT)
					{
						if ((GC.getImprovementInfo(eFinalImprovement).getRouteYieldChanges(eRoute, YIELD_FOOD) > 0) ||
							(GC.getImprovementInfo(eFinalImprovement).getRouteYieldChanges(eRoute, YIELD_PRODUCTION) > 0) ||
							(GC.getImprovementInfo(eFinalImprovement).getRouteYieldChanges(eRoute, YIELD_COMMERCE) > 0))
						{
							return true;
						}
					}
				}
			}
		}
	}

	if (GC.getActionInfo(iAction).getCommandType() == COMMAND_PROMOTION)
	{
		return true;
	}

	return false;
}


bool CvUnit::isBetterDefenderThan(const CvUnit* pDefender, const CvUnit* pAttacker) const
{
	int iOurDefense;
	int iTheirDefense;

	if (pDefender == NULL)
	{
		return true;
	}

	TeamTypes eAttackerTeam = NO_TEAM;
	if (NULL != pAttacker)
	{
		eAttackerTeam = pAttacker->getTeam();
	}

	if (canCoexistWithEnemyUnit(eAttackerTeam))
	{
		return false;
	}

	if (!canDefend())
	{
		return false;
	}

	if (canDefend() && !(pDefender->canDefend()))
	{
		return true;
	}

	if (pAttacker)
	{
		if (isTargetOf(*pAttacker) && !pDefender->isTargetOf(*pAttacker))
		{
			return true;
		}

		if (!isTargetOf(*pAttacker) && pDefender->isTargetOf(*pAttacker))
		{
			return false;
		}

		if (getDamage() >= pAttacker->combatLimit() && pDefender->getDamage() < pAttacker->combatLimit())
		{
			return false;
		}

		if (pDefender->getDamage() >= pAttacker->combatLimit() && getDamage() < pAttacker->combatLimit())
		{
			return true;
		}
	}

	iOurDefense = currCombatStr(plot(), pAttacker);
	if (::isWorldUnitClass(getUnitClassType()))
	{
		iOurDefense /= 2;
	}

	if (NULL == pAttacker)
	{
		if (pDefender->collateralDamage() > 0)
		{
			iOurDefense *= (100 + pDefender->collateralDamage());
			iOurDefense /= 100;
		}

		if (pDefender->currInterceptionProbability() > 0)
		{
			iOurDefense *= (100 + pDefender->currInterceptionProbability());
			iOurDefense /= 100;
		}
	}
	else
	{
		if (!(pAttacker->immuneToFirstStrikes()))
		{
			iOurDefense *= ((((firstStrikes() * 2) + chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iOurDefense /= 100;
		}

		if (immuneToFirstStrikes())
		{
			iOurDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iOurDefense /= 100;
		}
	}

	iOurDefense /= (getCargo() + 1);

	iTheirDefense = pDefender->currCombatStr(plot(), pAttacker);
	if (::isWorldUnitClass(pDefender->getUnitClassType()))
	{
		iTheirDefense /= 2;
	}

	if (NULL == pAttacker)
	{
		if (collateralDamage() > 0)
		{
			iTheirDefense *= (100 + collateralDamage());
			iTheirDefense /= 100;
		}

		if (currInterceptionProbability() > 0)
		{
			iTheirDefense *= (100 + currInterceptionProbability());
			iTheirDefense /= 100;
		}
	}
	else
	{
		if (!(pAttacker->immuneToFirstStrikes()))
		{
			iTheirDefense *= ((((pDefender->firstStrikes() * 2) + pDefender->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iTheirDefense /= 100;
		}

		if (pDefender->immuneToFirstStrikes())
		{
			iTheirDefense *= ((((pAttacker->firstStrikes() * 2) + pAttacker->chanceFirstStrikes()) * ((GC.getDefineINT("COMBAT_DAMAGE") * 2) / 5)) + 100);
			iTheirDefense /= 100;
		}
	}

	iTheirDefense /= (pDefender->getCargo() + 1);

//FfH Promotions: Added by Kael 07/30/2007
    iOurDefense *= getBetterDefenderThanPercent();
    iOurDefense /= 100;
    iTheirDefense *= pDefender->getBetterDefenderThanPercent();
    iTheirDefense /= 100;
//FfH Promotions: End Add

	if (iOurDefense == iTheirDefense)
	{
		if (NO_UNIT == getLeaderUnitType() && NO_UNIT != pDefender->getLeaderUnitType())
		{
			++iOurDefense;
		}
		else if (NO_UNIT != getLeaderUnitType() && NO_UNIT == pDefender->getLeaderUnitType())
		{
			++iTheirDefense;
		}
		else if (isBeforeUnitCycle(this, pDefender))
		{
			++iOurDefense;
		}
	}

	return (iOurDefense > iTheirDefense);
}


bool CvUnit::canDoCommand(CommandTypes eCommand, int iData1, int iData2, bool bTestVisible, bool bTestBusy)
{
	CvUnit* pUnit;

	if (bTestBusy && getGroup()->isBusy())
	{
		return false;
	}

	switch (eCommand)
	{
	case COMMAND_PROMOTION:
		if (canPromote((PromotionTypes)iData1, iData2))
		{
			return true;
		}
		break;

	case COMMAND_UPGRADE:
		if (canUpgrade(((UnitTypes)iData1), bTestVisible))
		{
			return true;
		}
		break;

	case COMMAND_AUTOMATE:
		if (canAutomate((AutomateTypes)iData1))
		{
			return true;
		}
		break;

	case COMMAND_WAKE:
		if (!isAutomated() && isWaiting())
		{
			return true;
		}
		break;

	case COMMAND_CANCEL:
	case COMMAND_CANCEL_ALL:
		if (!isAutomated() && (getGroup()->getLengthMissionQueue() > 0))
		{
			return true;
		}
		break;

	case COMMAND_STOP_AUTOMATION:
		if (isAutomated())
		{
			return true;
		}
		break;

	case COMMAND_DELETE:
		if (canScrap())
		{
			return true;
		}
		break;

	case COMMAND_GIFT:
		if (canGift(bTestVisible))
		{
			return true;
		}
		break;

	case COMMAND_LOAD:
		if (canLoad(plot()))
		{
			return true;
		}
		break;

	case COMMAND_LOAD_UNIT:
		pUnit = ::getUnit(IDInfo(((PlayerTypes)iData1), iData2));
		if (pUnit != NULL)
		{
			if (canLoadUnit(pUnit, plot()))
			{
				return true;
			}
		}
		break;

	case COMMAND_UNLOAD:
		if (canUnload())
		{
			return true;
		}
		break;

	case COMMAND_UNLOAD_ALL:
		if (canUnloadAll())
		{
			return true;
		}
		break;

	case COMMAND_HOTKEY:
		if (isGroupHead())
		{
			return true;
		}
		break;

//FfH Spell System: Added by Kael 07/23/2007
	case COMMAND_CAST:{
		if(canCast(iData1, bTestVisible))
		{
			return true;
		}
		break;
	}
//FfH: End Add

	default:
		FAssert(false);
		break;
	}

	return false;
}


void CvUnit::doCommand(CommandTypes eCommand, int iData1, int iData2)
{
	CvUnit* pUnit;
	bool bCycle;

	bCycle = false;

	FAssert(getOwnerINLINE() != NO_PLAYER);

	if (canDoCommand(eCommand, iData1, iData2))
	{
		switch (eCommand)
		{
		case COMMAND_PROMOTION:
			promote((PromotionTypes)iData1, iData2);
			break;

		case COMMAND_UPGRADE:
			upgrade((UnitTypes)iData1);
			bCycle = true;
			break;

		case COMMAND_AUTOMATE:
			automate((AutomateTypes)iData1);
			bCycle = true;
			break;

		case COMMAND_WAKE:
			getGroup()->setActivityType(ACTIVITY_AWAKE);
			break;

		case COMMAND_CANCEL:
			getGroup()->popMission();
			break;

		case COMMAND_CANCEL_ALL:
			getGroup()->clearMissionQueue();
			break;

		case COMMAND_STOP_AUTOMATION:
			getGroup()->setAutomateType(NO_AUTOMATE);
			break;

		case COMMAND_DELETE:
			scrap();
			bCycle = true;
			break;

		case COMMAND_GIFT:
			gift();
			bCycle = true;
			break;

		case COMMAND_LOAD:
			load();
			bCycle = true;
			break;

		case COMMAND_LOAD_UNIT:
			pUnit = ::getUnit(IDInfo(((PlayerTypes)iData1), iData2));
			if (pUnit != NULL)
			{
				loadUnit(pUnit);
				bCycle = true;
			}
			break;

		case COMMAND_UNLOAD:
			unload();
			bCycle = true;
			break;

		case COMMAND_UNLOAD_ALL:
			unloadAll();
			bCycle = true;
			break;

		case COMMAND_HOTKEY:
			setHotKeyNumber(iData1);
			break;

//FfH Spell System: Added by Kael 07/23/2007
		case COMMAND_CAST:{
			cast(iData1);
			break;
		}
//FfH: End Add

		default:
			FAssert(false);
			break;
		}
	}

	if (bCycle)
	{
		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setCycleSelectionCounter(1);
		}
	}

	getGroup()->doDelayedDeath();
}


FAStarNode* CvUnit::getPathLastNode() const
{
	return getGroup()->getPathLastNode();
}


CvPlot* CvUnit::getPathEndTurnPlot() const
{
	return getGroup()->getPathEndTurnPlot();
}


bool CvUnit::generatePath(const CvPlot* pToPlot, int iFlags, bool bReuse, int* piPathTurns) const
{
	return getGroup()->generatePath(plot(), pToPlot, iFlags, bReuse, piPathTurns);
}


bool CvUnit::canEnterTerritory(TeamTypes eTeam, bool bIgnoreRightOfPassage) const
{
	if (GET_TEAM(getTeam()).isFriendlyTerritory(eTeam))
	{
		return true;
	}

	if (eTeam == NO_TEAM)
	{
		return true;
	}

/*************************************************************************************************/
/**	Rivals (PromotionInfos)			05/15/08										Xienwolf	**/
/**																								**/
/**	Keeps RivalBlocked Units out of any Territory except Team, since that is already checked	**/
/*************************************************************************************************/
	if (isRivalTerritoryBlock())
	{
		return false;
	}

/*************************************************************************************************/
/**	Rivals (PromotionInfos)						END												**/
/*************************************************************************************************/
	if (isEnemy(eTeam))
	{
		return true;
	}

	if (isRivalTerritory())
	{
		return true;
	}

	if (alwaysInvisible())
	{
		return true;
	}

	if (!bIgnoreRightOfPassage)
	{
		if (GET_TEAM(getTeam()).isOpenBorders(eTeam))
		{
			return true;
		}
	}

//FfH: Added by Kael 09/02/2007 (so hidden nationality units can enter all territories)
    if (isHiddenNationality())
    {
        return true;
    }
    if (GET_TEAM(eTeam).isBarbarian()) // (so barbarians can enter player areas they are at peace with an vice versa)
    {
        return true;
    }
    if (GET_TEAM(getTeam()).isBarbarian())
    {
        return true;
    }
    if (GET_PLAYER(getOwnerINLINE()).isDeclaringWar())
    {
        if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != NO_RELIGION)
        {
            if (GC.getReligionInfo(GET_PLAYER(getOwnerINLINE()).getStateReligion()).isSneakAttack())
            {
                return true;
            }
        }
    }
//FfH: End Add

	return false;
}


bool CvUnit::canEnterArea(TeamTypes eTeam, const CvArea* pArea, bool bIgnoreRightOfPassage) const
{
	if (!canEnterTerritory(eTeam, bIgnoreRightOfPassage))
	{
		return false;
	}

	if (isBarbarian() && DOMAIN_LAND == getDomainType())
	{
		if (eTeam != NO_TEAM && eTeam != getTeam())
		{
			if (pArea && pArea->isBorderObstacle(eTeam))
			{
				return false;
			}
		}
	}

	return true;
}


// Returns the ID of the team to declare war against
TeamTypes CvUnit::getDeclareWarMove(const CvPlot* pPlot) const
{
	CvUnit* pUnit;
	TeamTypes eRevealedTeam;

	FAssert(isHuman());

/*************************************************************************************************/
/**	Rivals (PromotionInfos)			05/15/08										Xienwolf	**/
/**					Stops RivalBlocked Units from asking if you want to declare war				**/
/**								should you attempt to enter Territory							**/
/*************************************************************************************************/
	if (isRivalTerritoryBlock())
	{
		return NO_TEAM;
	}

/*************************************************************************************************/
/**	Rivals (PromotionInfos)						END												**/
/*************************************************************************************************/
	if (getDomainType() != DOMAIN_AIR)
	{
		eRevealedTeam = pPlot->getRevealedTeam(getTeam(), false);

		if (eRevealedTeam != NO_TEAM)
		{
			if (!canEnterArea(eRevealedTeam, pPlot->area()) || (getDomainType() == DOMAIN_SEA && !canCargoEnterArea(eRevealedTeam, pPlot->area(), false) && getGroup()->isAmphibPlot(pPlot)))
			{
				if (GET_TEAM(getTeam()).canDeclareWar(pPlot->getTeam()))
				{
					return eRevealedTeam;
				}
			}
		}
		else
		{
			if (pPlot->isActiveVisible(false))
			{
				if (canMoveInto(pPlot, true, true))
				{
					pUnit = pPlot->plotCheck(PUF_canDeclareWar, getOwnerINLINE(), isAlwaysHostile(pPlot), NO_PLAYER, NO_TEAM, PUF_isVisible, getOwnerINLINE());

					if (pUnit != NULL)
					{
						return pUnit->getTeam();
					}
				}
			}
		}
	}

	return NO_TEAM;
}

bool CvUnit::willRevealByMove(const CvPlot* pPlot) const
{
	int iRange = visibilityRange() + 1;
	for (int i = -iRange; i <= iRange; ++i)
	{
		for (int j = -iRange; j <= iRange; ++j)
		{
			CvPlot* pLoopPlot = ::plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), i, j);
			if (NULL != pLoopPlot)
			{
				if (!pLoopPlot->isRevealed(getTeam(), false) && pPlot->canSeePlot(pLoopPlot, getTeam(), visibilityRange(), NO_DIRECTION))
				{
					return true;
				}
			}
		}
	}

	return false;
}

bool CvUnit::canMoveInto(const CvPlot* pPlot, bool bAttack, bool bDeclareWar, bool bIgnoreLoad) const
{
	FAssertMsg(pPlot != NULL, "Plot is not assigned a valid value");

	if (atPlot(pPlot))
	{
		return false;
	}

	if (pPlot->isImpassable())
	{
		if (!canMoveImpassable())
		{
			return false;
		}
	}

	// Cannot move around in unrevealed land freely
/*************************************************************************************************/
/**	NoReveal (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**						Adds new Promotion Tag check to the old Unit Tag Check					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
	if (m_pUnitInfo->isNoRevealMap() && willRevealByMove(pPlot))
								----  End Original Code  ----									**/
	if ((m_pUnitInfo->isNoRevealMap() || isNoMapReveal()) && willRevealByMove(pPlot))
/*************************************************************************************************/
/**	No Reveal (PromotionInfos)					END												**/
/*************************************************************************************************/
	{
		return false;
	}

	if (GC.getUSE_SPIES_NO_ENTER_BORDERS())
	{
		if (isSpy() && NO_PLAYER != pPlot->getOwnerINLINE())
		{
			if (!GET_PLAYER(getOwnerINLINE()).canSpiesEnterBorders(pPlot->getOwnerINLINE()))
			{
				return false;
			}
		}
	}

	CvArea *pPlotArea = pPlot->area();
	TeamTypes ePlotTeam = pPlot->getTeam();
	bool bCanEnterArea = canEnterArea(ePlotTeam, pPlotArea);
	if (bCanEnterArea)
	{
		if (pPlot->getFeatureType() != NO_FEATURE)
		{
			if (m_pUnitInfo->getFeatureImpassable(pPlot->getFeatureType()))
			{
				TechTypes eTech = (TechTypes)m_pUnitInfo->getFeaturePassableTech(pPlot->getFeatureType());
				if (NO_TECH == eTech || !GET_TEAM(getTeam()).isHasTech(eTech))
				{
					if (DOMAIN_SEA != getDomainType() || pPlot->getTeam() != getTeam())  // sea units can enter impassable in own cultural borders
					{
						return false;
					}
				}
			}
		}
		else
		{
			if (m_pUnitInfo->getTerrainImpassable(pPlot->getTerrainType()))
			{
				TechTypes eTech = (TechTypes)m_pUnitInfo->getTerrainPassableTech(pPlot->getTerrainType());
				if (NO_TECH == eTech || !GET_TEAM(getTeam()).isHasTech(eTech))
				{
					if (DOMAIN_SEA != getDomainType() || pPlot->getTeam() != getTeam())  // sea units can enter impassable in own cultural borders
					{
						if (bIgnoreLoad || !canLoad(pPlot))
						{
							return false;
						}
					}
				}
			}
		}
	}

	switch (getDomainType())
	{
	case DOMAIN_SEA:
		if (!pPlot->isWater() && !canMoveAllTerrain())
		{
			if (!pPlot->isFriendlyCity(*this, true) || !pPlot->isCoastalLand())
			{
				return false;
			}
		}
		break;

	case DOMAIN_AIR:
		if (!bAttack)
		{
			bool bValid = false;

			if (pPlot->isFriendlyCity(*this, true))
			{
				bValid = true;

				if (m_pUnitInfo->getAirUnitCap() > 0)
				{
					if (pPlot->airUnitSpaceAvailable(getTeam()) <= 0)
					{
						bValid = false;
					}
				}
			}

			if (!bValid)
			{
				if (bIgnoreLoad || !canLoad(pPlot))
				{
					return false;
				}
			}
		}

		break;

	case DOMAIN_LAND:
		if (pPlot->isWater() && !canMoveAllTerrain()

//FfH: Added by Kael 08/27/2007 (for boarding)
              && !(bAttack && isBoarding())
//FfH: End Add

		)
		{
			if (!pPlot->isCity() || 0 == GC.getDefineINT("LAND_UNITS_CAN_ATTACK_WATER_CITIES"))
			{
				if (bIgnoreLoad || !isHuman() || plot()->isWater() || !canLoad(pPlot))
				{
					return false;
				}
			}
		}
		break;

	case DOMAIN_IMMOBILE:
		return false;
		break;

	default:
		FAssert(false);
		break;
	}

//FfH: Modified by Kael 08/04/2007 (So owned animals dont have limited movement)
//	if (isAnimal())
	if (isAnimal() && isBarbarian())
//FfH: End Add

	{
		if (pPlot->isOwned())
		{
			return false;
		}

		if (!bAttack)
		{
			if (pPlot->getBonusType() != NO_BONUS)
			{
				return false;
			}

			if (pPlot->getImprovementType() != NO_IMPROVEMENT)
			{
				return false;
			}

			if (pPlot->getNumUnits() > 0)
			{
				return false;
			}
		}
	}

	if (isNoCapture())
	{
		if (!bAttack)
		{
			if (pPlot->isEnemyCity(*this))
			{
				return false;
			}
		}
	}

	if (bAttack)
	{
		if (isMadeAttack() && !isBlitz())
		{
			return false;
		}
	}

	if (getDomainType() == DOMAIN_AIR)
	{
		if (bAttack)
		{
			if (!canAirStrike(pPlot))
			{
				return false;
			}
		}
	}
	else
	{
		if (canAttack())
		{
			if (bAttack || !canCoexistWithEnemyUnit(NO_TEAM))
			{
				if (!isHuman() || (pPlot->isVisible(getTeam(), false)))
				{
					if (pPlot->isVisibleEnemyUnit(this) != bAttack)
					{
						//FAssertMsg(isHuman() || (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE()) != bAttack)), "hopefully not an issue, but tracking how often this is the case when we dont want to really declare war");
						if (!bDeclareWar || (pPlot->isVisibleOtherUnit(getOwnerINLINE()) != bAttack && !(bAttack && pPlot->getPlotCity() && !isNoCapture())))
						{
							return false;
						}
					}
				}
			}

			if (bAttack)
			{
				CvUnit* pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);
				if (NULL != pDefender)
				{
					if (pDefender->getDamage() >= combatLimit())
					{
						return false;
					}
				}
			}
		}
		else
		{
			if (bAttack)
			{
				return false;
			}

			if (!canCoexistWithEnemyUnit(NO_TEAM))
			{
				if (!isHuman() || pPlot->isVisible(getTeam(), false))
				{
					if (pPlot->isEnemyCity(*this))
					{
						return false;
					}

					if (pPlot->isVisibleEnemyUnit(this))
					{
						return false;
					}
				}
			}
		}

		if (isHuman())
		{
			ePlotTeam = pPlot->getRevealedTeam(getTeam(), false);
			bCanEnterArea = canEnterArea(ePlotTeam, pPlotArea);
		}

		if (!bCanEnterArea)
		{
			FAssert(ePlotTeam != NO_TEAM);

			if (!(GET_TEAM(getTeam()).canDeclareWar(ePlotTeam)))
			{
				return false;
			}

			if (isHuman())
			{
				if (!bDeclareWar)
				{
					return false;
				}
			}
			else
			{
				if (GET_TEAM(getTeam()).AI_isSneakAttackReady(ePlotTeam))
				{
					if (!(getGroup()->AI_isDeclareWar(pPlot)))
					{
						return false;
					}
				}
				else
				{
					return false;
				}
			}
		}
	}

//FfH: Added by Kael 09/02/2007
    if (pPlot->getFeatureType() != NO_FEATURE)
    {
        if (GC.getFeatureInfo((FeatureTypes)pPlot->getFeatureType()).getRequireResist() != NO_DAMAGE)
        {
            if (getDamageTypeResist((DamageTypes)GC.getFeatureInfo((FeatureTypes)pPlot->getFeatureType()).getRequireResist()) < GC.getDefineINT("FEATURE_REQUIRE_RESIST_AMOUNT"))
            {
                return false;
            }
        }
    }
    if (pPlot->isOwned())
    {
        if (pPlot->getTeam() != getTeam())
        {
            if (GET_PLAYER(pPlot->getOwnerINLINE()).getSanctuaryTimer() != 0)
            {
                return false;
            }
        }
    }
    if (getLevel() < pPlot->getMinLevel())
    {
        return false;
    }
//FfH: End Add

	if (GC.getUSE_UNIT_CANNOT_MOVE_INTO_CALLBACK())
	{
		// Python Override
		CyArgsList argsList;
		argsList.add(getOwnerINLINE());	// Player ID
		argsList.add(getID());	// Unit ID
		argsList.add(pPlot->getX());	// Plot X
		argsList.add(pPlot->getY());	// Plot Y
		long lResult=0;
		gDLL->getPythonIFace()->callFunction(PYGameModule, "unitCannotMoveInto", argsList.makeFunctionArgs(), &lResult);

		if (lResult != 0)
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::canMoveOrAttackInto(const CvPlot* pPlot, bool bDeclareWar) const
{
	return (canMoveInto(pPlot, false, bDeclareWar) || canMoveInto(pPlot, true, bDeclareWar));
}


bool CvUnit::canMoveThrough(const CvPlot* pPlot) const
{
	return canMoveInto(pPlot, false, false, true);
}


void CvUnit::attack(CvPlot* pPlot, bool bQuick)
{
	FAssert(canMoveInto(pPlot, true));
	FAssert(getCombatTimer() == 0);

	setAttackPlot(pPlot, false);

	updateCombat(bQuick);
}

void CvUnit::fightInterceptor(const CvPlot* pPlot, bool bQuick)
{
	FAssert(getCombatTimer() == 0);

	setAttackPlot(pPlot, true);

	updateAirCombat(bQuick);
}

void CvUnit::attackForDamage(CvUnit *pDefender, int attackerDamageChange, int defenderDamageChange)
{
	FAssert(getCombatTimer() == 0);
	FAssert(pDefender != NULL);
	FAssert(!isFighting());

	if(pDefender == NULL)
	{
		return;
	}

	setAttackPlot(pDefender->plot(), false);

	CvPlot* pPlot = getAttackPlot();
	if (pPlot == NULL)
	{
		return;
	}

	//rotate to face plot
	DirectionTypes newDirection = estimateDirection(this->plot(), pDefender->plot());
	if(newDirection != NO_DIRECTION)
	{
		setFacingDirection(newDirection);
	}

	//rotate enemy to face us
	newDirection = estimateDirection(pDefender->plot(), this->plot());
	if(newDirection != NO_DIRECTION)
	{
		pDefender->setFacingDirection(newDirection);
	}

	//check if quick combat
	bool bVisible = isCombatVisible(pDefender);

	//if not finished and not fighting yet, set up combat damage and mission
	if (!isFighting())
	{
		if (plot()->isFighting() || pPlot->isFighting())
		{
			return;
		}

		setCombatUnit(pDefender, true);
		pDefender->setCombatUnit(this, false);

		pDefender->getGroup()->clearMissionQueue();

		bool bFocused = (bVisible && isCombatFocus() && gDLL->getInterfaceIFace()->isCombatFocus());

		if (bFocused)
		{
			DirectionTypes directionType = directionXY(plot(), pPlot);
			//								N			NE				E				SE					S				SW					W				NW
			NiPoint2 directions[8] = {NiPoint2(0, 1), NiPoint2(1, 1), NiPoint2(1, 0), NiPoint2(1, -1), NiPoint2(0, -1), NiPoint2(-1, -1), NiPoint2(-1, 0), NiPoint2(-1, 1)};
			NiPoint3 attackDirection = NiPoint3(directions[directionType].x, directions[directionType].y, 0);
			float plotSize = GC.getPLOT_SIZE();
			NiPoint3 lookAtPoint(plot()->getPoint().x + plotSize / 2 * attackDirection.x, plot()->getPoint().y + plotSize / 2 * attackDirection.y, (plot()->getPoint().z + pPlot->getPoint().z) / 2);
			attackDirection.Unitize();
			gDLL->getInterfaceIFace()->lookAt(lookAtPoint, (((getOwnerINLINE() != GC.getGameINLINE().getActivePlayer()) || gDLL->getGraphicOption(GRAPHICOPTION_NO_COMBAT_ZOOM)) ? CAMERALOOKAT_BATTLE : CAMERALOOKAT_BATTLE_ZOOM_IN), attackDirection);
		}
		else
		{
			PlayerTypes eAttacker = getVisualOwner(pDefender->getTeam());
			CvWString szMessage;
			if (BARBARIAN_PLAYER != eAttacker)
			{
				szMessage = gDLL->getText("TXT_KEY_MISC_YOU_UNITS_UNDER_ATTACK", GET_PLAYER(getOwnerINLINE()).getNameKey());
			}
			else
			{
				szMessage = gDLL->getText("TXT_KEY_MISC_YOU_UNITS_UNDER_ATTACK_UNKNOWN");
			}

			gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szMessage, "AS2D_COMBAT", MESSAGE_TYPE_DISPLAY_ONLY, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true);
		}
	}

	FAssertMsg(plot()->isFighting(), "Current unit instance plot is not fighting as expected");
	FAssertMsg(pPlot->isFighting(), "pPlot is not fighting as expected");

	//setup battle object
	CvBattleDefinition kBattle;
	kBattle.setUnit(BATTLE_UNIT_ATTACKER, this);
	kBattle.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
	kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_BEGIN, getDamage());
	kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_BEGIN, pDefender->getDamage());

	changeDamage(attackerDamageChange, pDefender->getOwnerINLINE());
	pDefender->changeDamage(defenderDamageChange, getOwnerINLINE());

	if (bVisible)
	{
		kBattle.setDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_END, getDamage());
		kBattle.setDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_END, pDefender->getDamage());
		kBattle.setAdvanceSquare(canAdvance(pPlot, 1));

		kBattle.addDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_ATTACKER, BATTLE_TIME_BEGIN));
		kBattle.addDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_RANGED, kBattle.getDamage(BATTLE_UNIT_DEFENDER, BATTLE_TIME_BEGIN));

		int iTurns = planBattle( kBattle);
		kBattle.setMissionTime(iTurns * gDLL->getSecsPerTurn());
		setCombatTimer(iTurns);

		GC.getGameINLINE().incrementTurnTimer(getCombatTimer());

		if (pPlot->isActiveVisible(false))
		{
			ExecuteMove(0.5f, true);
			gDLL->getEntityIFace()->AddMission(&kBattle);
		}
	}
	else
	{
		setCombatTimer(1);
	}
}


void CvUnit::move(CvPlot* pPlot, bool bShow)
{
	FAssert(canMoveOrAttackInto(pPlot) || isMadeAttack());

	CvPlot* pOldPlot = plot();

	changeMoves(pPlot->movementCost(this, plot()));

	setXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true, bShow && pPlot->isVisibleToWatchingHuman(), bShow);

	//change feature
	FeatureTypes featureType = pPlot->getFeatureType();
	if(featureType != NO_FEATURE)
	{
		CvString featureString(GC.getFeatureInfo(featureType).getOnUnitChangeTo());
		if(!featureString.IsEmpty())
		{
			FeatureTypes newFeatureType = (FeatureTypes) GC.getInfoTypeForString(featureString);
			pPlot->setFeatureType(newFeatureType);
		}
	}

	if (getOwnerINLINE() == GC.getGameINLINE().getActivePlayer())
	{
		if (!(pPlot->isOwned()))
		{
			//spawn birds if trees present - JW
			if (featureType != NO_FEATURE)
			{
				if (GC.getASyncRand().get(100) < GC.getFeatureInfo(featureType).getEffectProbability())
				{
					EffectTypes eEffect = (EffectTypes)GC.getInfoTypeForString(GC.getFeatureInfo(featureType).getEffectType());
					gDLL->getEngineIFace()->TriggerEffect(eEffect, pPlot->getPoint(), (float)(GC.getASyncRand().get(360)));
					gDLL->getInterfaceIFace()->playGeneralSound("AS3D_UN_BIRDS_SCATTER", pPlot->getPoint());
				}
			}
		}
	}

//FfH Units: Added by Kael 08/07/2007
    if (pPlot->getImprovementType() != NO_IMPROVEMENT)
    {
        if (GC.getImprovementInfo((ImprovementTypes)pPlot->getImprovementType()).getSpawnUnitType() != NO_UNIT)
        {
            if (!GC.getImprovementInfo((ImprovementTypes)pPlot->getImprovementType()).isPermanent())
            {
                if (atWar(getTeam(), GET_PLAYER(BARBARIAN_PLAYER).getTeam()))
                {
                    gDLL->getInterfaceIFace()->addMessage(getOwner(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), gDLL->getText("TXT_KEY_MESSAGE_LAIR_DESTROYED"), "AS2D_CITYRAZE", MESSAGE_TYPE_MAJOR_EVENT, GC.getImprovementInfo(pPlot->getImprovementType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                    pPlot->setImprovementType(NO_IMPROVEMENT);
                }
            }
        }
    }
    if (pPlot->isCity() && m_pUnitInfo->getWeaponTier() > 0)
    {
        if (getOwner() == pPlot->getOwner())
        {
            setWeapons();
        }
    }
/*************************************************************************************************/
/**	SelfPillage (PromotionInfos)	05/15/08										Xienwolf	**/
/**				Makes a Unit automatically Pillage in Team controlled or Neutral Territory		**/
/**					Demotes Improvements along Pillage Tree, then Takes out Routes				**/
/*************************************************************************************************/
    if (isSelfPillage())
    {
        if (!(pPlot->isOwned()) || getTeam() == pPlot->getTeam())
        {
            CvWString szBuffer;
            ImprovementTypes eTempImprovement = NO_IMPROVEMENT;
            RouteTypes eTempRoute = NO_ROUTE;

            if (pPlot->getImprovementType() != NO_IMPROVEMENT)
            {
                if (!GC.getImprovementInfo((ImprovementTypes)pPlot->getImprovementType()).isPermanent())
                {
                    eTempImprovement = pPlot->getImprovementType();
                    szBuffer = gDLL->getText("TXT_KEY_MISC_IMP_DESTROYED", GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide(), getNameKey(), getVisualCivAdjective(pPlot->getTeam()));
                    gDLL->getInterfaceIFace()->addMessage(pPlot->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
                    pPlot->setImprovementType((ImprovementTypes)(GC.getImprovementInfo(pPlot->getImprovementType()).getImprovementPillage()));
                }
            }
            else if (pPlot->isRoute())
            {
                eTempRoute = pPlot->getRouteType();
                pPlot->setRouteType(NO_ROUTE, true);
            }
            if (eTempImprovement != NO_IMPROVEMENT || eTempRoute != NO_ROUTE)
            {
                gDLL->getEventReporterIFace()->unitPillage(this, eTempImprovement, eTempRoute, getOwnerINLINE());
            }
        }
    }
/*************************************************************************************************/
/**	SelfPillage (PromotionInfos)				END												**/
/*************************************************************************************************/

/*************************************************************************************************/
/**	AutoPillage (PromotionInfos)	05/15/08										Xienwolf	**/
/**																								**/
/**						Adds new Promotion Tag check to the old Unit Tag Check					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
    if (m_pUnitInfo->isAutoRaze())
								----  End Original Code  ----									**/
    if (m_pUnitInfo->isAutoRaze() || isPillageOnMove())
/*************************************************************************************************/
/**	AutoPillage (PromotionInfos)				END												**/
/*************************************************************************************************/
    {
        if (pPlot->isOwned())
        {
            if (pPlot->getImprovementType() != NO_IMPROVEMENT)
            {
                if (!GC.getImprovementInfo((ImprovementTypes)pPlot->getImprovementType()).isPermanent())
                {
                    if (atWar(getTeam(), GET_PLAYER(pPlot->getOwner()).getTeam()))
                    {
/*************************************************************************************************/
/**	AutoPillage (PromotionInfos)	05/15/08										Xienwolf	**/
/**					Lots of Code here to change from the Old "No Cash, Full Destroy"			**/
/**					to the new "Pillage without Spending Movement or getting a choice"			**/
/*************************************************************************************************/
/**								---- Start Original Code ----
                        pPlot->setImprovementType(NO_IMPROVEMENT);
								----  End Original Code  ----									**/
                        CvWString szBuffer;
                        int iPillageGold;
                        long lPillageGold;
                        lPillageGold = 0;

                        CyPlot* pyPlot = new CyPlot(pPlot);
                        CyUnit* pyUnit = new CyUnit(this);

                        CyArgsList argsList;
                        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyPlot));	// pass in plot class
                        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class

                        gDLL->getPythonIFace()->callFunction(PYGameModule, "doPillageGold", argsList.makeFunctionArgs(),&lPillageGold);

                        delete pyPlot;	// python fxn must not hold on to this pointer
                        delete pyUnit;	// python fxn must not hold on to this pointer

                        iPillageGold = (int)lPillageGold;

                        if (iPillageGold > 0)
                        {
                            iPillageGold += (iPillageGold * GET_PLAYER(getOwnerINLINE()).getPillagingGold()) / 100;

                            GET_PLAYER(getOwnerINLINE()).changeGold(iPillageGold);

                            szBuffer = gDLL->getText("TXT_KEY_MISC_PLUNDERED_GOLD_FROM_IMP", iPillageGold, GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide());
                            gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

                            if (pPlot->isOwned())
                            {
                                szBuffer = gDLL->getText("TXT_KEY_MISC_IMP_DESTROYED", GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide(), getNameKey(), getVisualCivAdjective(pPlot->getTeam()));
                                gDLL->getInterfaceIFace()->addMessage(pPlot->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
                            }
                            gDLL->getEventReporterIFace()->unitPillage(this, pPlot->getImprovementType(), NO_ROUTE, getOwnerINLINE());
                            pPlot->setImprovementType((ImprovementTypes)(GC.getImprovementInfo(pPlot->getImprovementType()).getImprovementPillage()));
                        }
/*************************************************************************************************/
/**	AutoPillage (PromotionInfos)				END												**/
/*************************************************************************************************/
                    }
                }
            }
        }
/*************************************************************************************************/
/**	AutoPillage (PromotionInfos)	05/15/08										Xienwolf	**/
/**																								**/
/**					Allows Unit Tag to destroy Features as well as Pillage Improvements			**/
/*************************************************************************************************/
    }
    if (m_pUnitInfo->isAutoRaze())
    {
/*************************************************************************************************/
/**	AutoPillage (PromotionInfos)				END												**/
/*************************************************************************************************/
        pPlot->setFeatureType(NO_FEATURE, -1);
    }
//FfH: End Add

	gDLL->getEventReporterIFace()->unitMove(pPlot, this, pOldPlot);
}

// false if unit is killed
bool CvUnit::jumpToNearestValidPlot()
{
	CvCity* pNearestCity;
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot;
	int iValue;
	int iBestValue;
	int iI;

	FAssertMsg(!isAttacking(), "isAttacking did not return false as expected");
	FAssertMsg(!isFighting(), "isFighting did not return false as expected");

	pNearestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE());

	iBestValue = MAX_INT;
	pBestPlot = NULL;

	for (iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);

		if (pLoopPlot->isValidDomainForLocation(*this))
		{
			if (canMoveInto(pLoopPlot))
			{
				if (canEnterArea(pLoopPlot->getTeam(), pLoopPlot->area()) && !isEnemy(pLoopPlot->getTeam(), pLoopPlot))
				{
					FAssertMsg(!atPlot(pLoopPlot), "atPlot(pLoopPlot) did not return false as expected");

					if ((getDomainType() != DOMAIN_AIR) || pLoopPlot->isFriendlyCity(*this, true))
					{
						if (pLoopPlot->isRevealed(getTeam(), false))
						{
							iValue = (plotDistance(getX_INLINE(), getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) * 2);

							if (pNearestCity != NULL)
							{
								iValue += plotDistance(pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE(), pNearestCity->getX_INLINE(), pNearestCity->getY_INLINE());
							}

							if (pLoopPlot->area() != area())
							{
								iValue *= 3;
							}

							if (iValue < iBestValue)
							{
								iBestValue = iValue;
								pBestPlot = pLoopPlot;
							}
						}
					}
				}
			}
		}
	}

	bool bValid = true;
	if (pBestPlot != NULL)
	{
		setXY(pBestPlot->getX_INLINE(), pBestPlot->getY_INLINE());
	}
	else
	{
		kill(false);
		bValid = false;
	}

	return bValid;
}


bool CvUnit::canAutomate(AutomateTypes eAutomate) const
{
	if (eAutomate == NO_AUTOMATE)
	{
		return false;
	}

	if (!isGroupHead())
	{
		return false;
	}

	switch (eAutomate)
	{
	case AUTOMATE_BUILD:
		if ((AI_getUnitAIType() != UNITAI_WORKER) && (AI_getUnitAIType() != UNITAI_WORKER_SEA))
		{
			return false;
		}
		break;

	case AUTOMATE_NETWORK:
		if ((AI_getUnitAIType() != UNITAI_WORKER) || !canBuildRoute())
		{
			return false;
		}
		break;

	case AUTOMATE_CITY:
		if (AI_getUnitAIType() != UNITAI_WORKER)
		{
			return false;
		}
		break;

	case AUTOMATE_EXPLORE:
		if ((!canFight() && (getDomainType() != DOMAIN_SEA)) || (getDomainType() == DOMAIN_AIR) || (getDomainType() == DOMAIN_IMMOBILE))
		{
			return false;
		}
		break;

	case AUTOMATE_RELIGION:
		if (AI_getUnitAIType() != UNITAI_MISSIONARY)
		{
			return false;
		}
		break;

	default:
		FAssert(false);
		break;
	}

	return true;
}


void CvUnit::automate(AutomateTypes eAutomate)
{
	if (!canAutomate(eAutomate))
	{
		return;
	}

	getGroup()->setAutomateType(eAutomate);
}


bool CvUnit::canScrap() const
{
	if (plot()->isFighting())
	{
		return false;
	}

//FfH: Added by Kael 11/06/2007
    if (GET_PLAYER(getOwnerINLINE()).getTempPlayerTimer() > 0)
    {
        return false;
    }
    if (m_pUnitInfo->getEquipmentPromotion() != NO_PROMOTION)
    {
        return false;
    }
//FfH: End Add

	return true;
}


void CvUnit::scrap()
{
	if (!canScrap())
	{
		return;
	}

//FfH: Added by Kael 11/04/2007
	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
	    if (isHasPromotion((PromotionTypes)iI))
	    {
            if (GC.getPromotionInfo((PromotionTypes)iI).getBetrayalChance() != 0)
            {
                betray(BARBARIAN_PLAYER);
            }
        }
	}
//FfH: End Add

	kill(true);
}


bool CvUnit::canGift(bool bTestVisible, bool bTestTransport)
{

//FfH: Added by Kael 04/22/2008 (to disable gifting)
    return false;
//FfH: End Add

	CvPlot* pPlot = plot();
	CvUnit* pTransport = getTransportUnit();

	if (!(pPlot->isOwned()))
	{
		return false;
	}

	if (pPlot->getOwnerINLINE() == getOwnerINLINE())
	{
		return false;
	}

	if (pPlot->isVisibleEnemyUnit(this))
	{
		return false;
	}

	if (pPlot->isVisibleEnemyUnit(pPlot->getOwnerINLINE()))
	{
		return false;
	}

	if (!pPlot->isValidDomainForLocation(*this) && NULL == pTransport)
	{
		return false;
	}

	for (int iCorp = 0; iCorp < GC.getNumCorporationInfos(); ++iCorp)
	{
		if (m_pUnitInfo->getCorporationSpreads(iCorp) > 0)
		{
			return false;
		}
	}

	if (bTestTransport)
	{
		if (pTransport && pTransport->getTeam() != pPlot->getTeam())
		{
			return false;
		}
	}

	if (!bTestVisible)
	{
		if (GET_TEAM(pPlot->getTeam()).isUnitClassMaxedOut(getUnitClassType(), GET_TEAM(pPlot->getTeam()).getUnitClassMaking(getUnitClassType())))
		{
			return false;
		}

		if (GET_PLAYER(pPlot->getOwnerINLINE()).isUnitClassMaxedOut(getUnitClassType(), GET_PLAYER(pPlot->getOwnerINLINE()).getUnitClassMaking(getUnitClassType())))
		{
			return false;
		}

		if (!(GET_PLAYER(pPlot->getOwnerINLINE()).AI_acceptUnit(this)))
		{
			return false;
		}
	}

//FfH: Added by Kael 11/06/2007
    if (GET_PLAYER(getOwnerINLINE()).getTempPlayerTimer() > 0)
    {
        return false;
    }
//FfH: End Add

	return !atWar(pPlot->getTeam(), getTeam());
}


void CvUnit::gift(bool bTestTransport)
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pGiftUnit;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;
	CvWString szBuffer;
	PlayerTypes eOwner;

	if (!canGift(false, bTestTransport))
	{
		return;
	}

	pPlot = plot();

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			pLoopUnit->gift(false);
		}
	}

	FAssertMsg(plot()->getOwnerINLINE() != NO_PLAYER, "plot()->getOwnerINLINE() is not expected to be equal with NO_PLAYER");
	pGiftUnit = GET_PLAYER(plot()->getOwnerINLINE()).initUnit(getUnitType(), getX_INLINE(), getY_INLINE(), AI_getUnitAIType());

	FAssertMsg(pGiftUnit != NULL, "GiftUnit is not assigned a valid value");

	eOwner = getOwnerINLINE();

	pGiftUnit->convert(this);

	GET_PLAYER(pGiftUnit->getOwnerINLINE()).AI_changePeacetimeGrantValue(eOwner, (pGiftUnit->getUnitInfo().getProductionCost() / 5));

	szBuffer = gDLL->getText("TXT_KEY_MISC_GIFTED_UNIT_TO_YOU", GET_PLAYER(eOwner).getNameKey(), pGiftUnit->getNameKey());
	gDLL->getInterfaceIFace()->addMessage(pGiftUnit->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_UNITGIFTED", MESSAGE_TYPE_INFO, pGiftUnit->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), pGiftUnit->getX_INLINE(), pGiftUnit->getY_INLINE(), true, true);

	// Python Event
	gDLL->getEventReporterIFace()->unitGifted(pGiftUnit, getOwnerINLINE(), plot());
}


bool CvUnit::canLoadUnit(const CvUnit* pUnit, const CvPlot* pPlot) const
{
	FAssert(pUnit != NULL);
	FAssert(pPlot != NULL);

	if (pUnit == this)
	{
		return false;
	}

	if (pUnit->getTeam() != getTeam())
	{
		return false;
	}

	if (getCargo() > 0)
	{
		return false;
	}

	if (pUnit->isCargo())
	{
		return false;
	}

	if (!(pUnit->cargoSpaceAvailable(getSpecialUnitType(), getDomainType())))
	{
		return false;
	}

	if (!(pUnit->atPlot(pPlot)))
	{
		return false;
	}

//FfH Hidden Nationality: Modified by Kael 08/27/2007
//	if (!m_pUnitInfo->isHiddenNationality() && pUnit->getUnitInfo().isHiddenNationality())
	if (!isHiddenNationality() && pUnit->isHiddenNationality())
//FfH: End Modify

	{
		return false;
	}

	return true;
}


void CvUnit::loadUnit(CvUnit* pUnit)
{
	if (!canLoadUnit(pUnit, plot()))
	{
		return;
	}

	setTransportUnit(pUnit);
}

bool CvUnit::shouldLoadOnMove(const CvPlot* pPlot) const
{
	if (isCargo())
	{
		return false;
	}

	switch (getDomainType())
	{
	case DOMAIN_LAND:
		if (pPlot->isWater())
		{
			return true;
		}
		break;
	case DOMAIN_AIR:
		if (!pPlot->isFriendlyCity(*this, true))
		{
			return true;
		}

		if (m_pUnitInfo->getAirUnitCap() > 0)
		{
			if (pPlot->airUnitSpaceAvailable(getTeam()) <= 0)
			{
				return true;
			}
		}
		break;
	default:
		break;
	}

	if (m_pUnitInfo->getTerrainImpassable(pPlot->getTerrainType()))
	{
		TechTypes eTech = (TechTypes)m_pUnitInfo->getTerrainPassableTech(pPlot->getTerrainType());
		if (NO_TECH == eTech || !GET_TEAM(getTeam()).isHasTech(eTech))
		{
			return true;
		}
	}

	return false;
}


bool CvUnit::canLoad(const CvPlot* pPlot) const
{
	PROFILE_FUNC();

	FAssert(pPlot != NULL);

	if (NO_SPECIALUNIT != getSpecialUnitType())
	{
		if (GC.getSpecialUnitInfo(getSpecialUnitType()).isCityLoad())
		{
			if (!pPlot->isCity(true, getTeam()))
			{
				return false;
			}
		}
	}

	CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (canLoadUnit(pLoopUnit, pPlot))
		{
			return true;
		}
	}

	return false;
}


void CvUnit::load()
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;
	int iPass;

	if (!canLoad(plot()))
	{
		return;
	}

	pPlot = plot();

	for (iPass = 0; iPass < 2; iPass++)
	{
		pUnitNode = pPlot->headUnitNode();

		while (pUnitNode != NULL)
		{
			pLoopUnit = ::getUnit(pUnitNode->m_data);
			pUnitNode = pPlot->nextUnitNode(pUnitNode);

			if (canLoadUnit(pLoopUnit, pPlot))
			{
				if ((iPass == 0) ? (pLoopUnit->getOwnerINLINE() == getOwnerINLINE()) : (pLoopUnit->getTeam() == getTeam()))
				{
					setTransportUnit(pLoopUnit);
					break;
				}
			}
		}

		if (isCargo())
		{
			break;
		}
	}
}


bool CvUnit::canUnload() const
{
	CvPlot& kPlot = *(plot());

	if (getTransportUnit() == NULL)
	{
		return false;
	}

	if (!kPlot.isValidDomainForLocation(*this))
	{
		return false;
	}

	if (getDomainType() == DOMAIN_AIR)
	{
		if (kPlot.isFriendlyCity(*this, true))
		{
			int iNumAirUnits = kPlot.countNumAirUnits(getTeam());
			CvCity* pCity = kPlot.getPlotCity();
			if (NULL != pCity)
			{
				if (iNumAirUnits >= pCity->getAirUnitCapacity(getTeam()))
				{
					return false;
				}
			}
			else
			{
				if (iNumAirUnits >= GC.getDefineINT("CITY_AIR_UNIT_CAPACITY"))
				{
					return false;
				}
			}
		}
	}

	return true;
}


void CvUnit::unload()
{
	if (!canUnload())
	{
		return;
	}

	setTransportUnit(NULL);
}


bool CvUnit::canUnloadAll() const
{
	if (getCargo() == 0)
	{
		return false;
	}

	return true;
}


void CvUnit::unloadAll()
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;

	if (!canUnloadAll())
	{
		return;
	}

	pPlot = plot();

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (pLoopUnit->canUnload())
			{
				pLoopUnit->setTransportUnit(NULL);
			}
			else
			{
				FAssert(isHuman() || pLoopUnit->getDomainType() == DOMAIN_AIR);
				pLoopUnit->getGroup()->setActivityType(ACTIVITY_AWAKE);
			}
		}
	}
}


bool CvUnit::canHold(const CvPlot* pPlot) const
{
	return true;
}


bool CvUnit::canSleep(const CvPlot* pPlot) const
{
	if (isFortifyable())
	{
		return false;
	}

	if (isWaiting())
	{
		return false;
	}

	return true;
}


bool CvUnit::canFortify(const CvPlot* pPlot) const
{
	if (!isFortifyable())
	{
		return false;
	}

	if (isWaiting())
	{
		return false;
	}

	return true;
}


bool CvUnit::canAirPatrol(const CvPlot* pPlot) const
{
	if (getDomainType() != DOMAIN_AIR)
	{
		return false;
	}

	if (!canAirDefend(pPlot))
	{
		return false;
	}

	if (isWaiting())
	{
		return false;
	}

	return true;
}


bool CvUnit::canSeaPatrol(const CvPlot* pPlot) const
{
	if (!pPlot->isWater())
	{
		return false;
	}

	if (getDomainType() != DOMAIN_SEA)
	{
		return false;
	}

	if (!canFight() || isOnlyDefensive())
	{
		return false;
	}

	if (isWaiting())
	{
		return false;
	}

	return true;
}


void CvUnit::airCircle(bool bStart)
{
	if (!GC.IsGraphicsInitialized())
	{
		return;
	}

	if ((getDomainType() != DOMAIN_AIR) || (maxInterceptionProbability() == 0))
	{
		return;
	}

	//cancel previos missions
	gDLL->getEntityIFace()->RemoveUnitFromBattle( this );

	if (bStart)
	{
		CvAirMissionDefinition kDefinition;
		kDefinition.setPlot(plot());
		kDefinition.setUnit(BATTLE_UNIT_ATTACKER, this);
		kDefinition.setUnit(BATTLE_UNIT_DEFENDER, NULL);
		kDefinition.setMissionType(MISSION_AIRPATROL);
		kDefinition.setMissionTime(1.0f); // patrol is indefinite - time is ignored

		gDLL->getEntityIFace()->AddMission( &kDefinition );
	}
}


bool CvUnit::canHeal(const CvPlot* pPlot) const
{
	if (!isHurt())
	{
		return false;
	}

	if (isWaiting())
	{
		return false;
	}

	if (healRate(pPlot) <= 0)
	{
		return false;
	}

	return true;
}


bool CvUnit::canSentry(const CvPlot* pPlot) const
{
	if (!canDefend(pPlot))
	{
		return false;
	}

	if (isWaiting())
	{
		return false;
	}

	return true;
}


int CvUnit::healRate(const CvPlot* pPlot) const
{
	PROFILE_FUNC();

	CLLNode<IDInfo>* pUnitNode;
	CvCity* pCity;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
	int iTotalHeal;
	int iHeal;
	int iBestHeal;
	int iI;

	pCity = pPlot->getPlotCity();

	iTotalHeal = 0;

	if (pPlot->isCity(true, getTeam()))
	{
		iTotalHeal += GC.getDefineINT("CITY_HEAL_RATE") + (GET_TEAM(getTeam()).isFriendlyTerritory(pPlot->getTeam()) ? getExtraFriendlyHeal() : getExtraNeutralHeal());
		if (pCity && !pCity->isOccupation())
		{
			iTotalHeal += pCity->getHealRate();
		}
	}
	else
	{
		if (!GET_TEAM(getTeam()).isFriendlyTerritory(pPlot->getTeam()))
		{
			if (isEnemy(pPlot->getTeam(), pPlot))
			{
				iTotalHeal += (GC.getDefineINT("ENEMY_HEAL_RATE") + getExtraEnemyHeal());

//FfH Mana Effects: Added by Kael 08/21/2007
                iTotalHeal += GET_PLAYER(pPlot->getOwnerINLINE()).getHealChangeEnemy();
//FfH: End Add

			}
			else
			{
				iTotalHeal += (GC.getDefineINT("NEUTRAL_HEAL_RATE") + getExtraNeutralHeal());
			}
		}
		else
		{
			iTotalHeal += (GC.getDefineINT("FRIENDLY_HEAL_RATE") + getExtraFriendlyHeal());

//FfH Mana Effects: Added by Kael 08/21/2007
            iTotalHeal += GET_PLAYER(getOwnerINLINE()).getHealChange();
//FfH: End Add

		}
	}

	// XXX optimize this (save it?)
	iBestHeal = 0;

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTeam() == getTeam()) // XXX what about alliances?
		{
			iHeal = pLoopUnit->getSameTileHeal();

			if (iHeal > iBestHeal)
			{
				iBestHeal = iHeal;
			}
		}
	}

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));

		if (pLoopPlot != NULL)
		{
			if (pLoopPlot->area() == pPlot->area())
			{
				pUnitNode = pLoopPlot->headUnitNode();

				while (pUnitNode != NULL)
				{
					pLoopUnit = ::getUnit(pUnitNode->m_data);
					pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);

					if (pLoopUnit->getTeam() == getTeam()) // XXX what about alliances?
					{
						iHeal = pLoopUnit->getAdjacentTileHeal();

						if (iHeal > iBestHeal)
						{
							iBestHeal = iHeal;
						}
					}
				}
			}
		}
	}

	iTotalHeal += iBestHeal;
	// XXX

//FfH: Added by Kael 10/29/2007
    if (pPlot->getImprovementType() != NO_IMPROVEMENT)
    {
        iTotalHeal += GC.getImprovementInfo((ImprovementTypes)pPlot->getImprovementType()).getHealRateChange();
    }
    if (iTotalHeal < 0)
    {
        iTotalHeal = 0;
    }
//FfH: End Add

	return iTotalHeal;
}


int CvUnit::healTurns(const CvPlot* pPlot) const
{
	int iHeal;
	int iTurns;

	if (!isHurt())
	{
		return 0;
	}

	iHeal = healRate(pPlot);

	if (iHeal > 0)
	{
		iTurns = (getDamage() / iHeal);

		if ((getDamage() % iHeal) != 0)
		{
			iTurns++;
		}

		return iTurns;
	}
	else
	{
		return MAX_INT;
	}
}


void CvUnit::doHeal()
{
	changeDamage(-(healRate(plot())));

//FfH: Added by Kael 07/30/2007
    if (getDamage() == 0)
    {
        for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
        {
            if (isHasPromotion((PromotionTypes)iI))
            {
                if (GC.getPromotionInfo((PromotionTypes)iI).isRemovedWhenHealed())
                {
                    setHasPromotion(((PromotionTypes)iI), false);
                }
		    }
		}
	}
//FfH: End Add

}


bool CvUnit::canAirlift(const CvPlot* pPlot) const
{
	CvCity* pCity;

	if (getDomainType() != DOMAIN_LAND)
	{
		return false;
	}

	if (hasMoved())
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getCurrAirlift() >= pCity->getMaxAirlift())
	{
		return false;
	}

	if (pCity->getTeam() != getTeam())
	{
		return false;
	}

	return true;
}


bool CvUnit::canAirliftAt(const CvPlot* pPlot, int iX, int iY) const
{
	CvPlot* pTargetPlot;
	CvCity* pTargetCity;

	if (!canAirlift(pPlot))
	{
		return false;
	}

	pTargetPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	if (!canMoveInto(pTargetPlot))
	{
		return false;
	}

	pTargetCity = pTargetPlot->getPlotCity();

	if (pTargetCity == NULL)
	{
		return false;
	}

	if (pTargetCity->isAirliftTargeted())
	{
		return false;
	}

	if (pTargetCity->getTeam() != getTeam() && !GET_TEAM(pTargetCity->getTeam()).isVassal(getTeam()))
	{
		return false;
	}

	return true;
}


bool CvUnit::airlift(int iX, int iY)
{
	CvCity* pCity;
	CvCity* pTargetCity;
	CvPlot* pTargetPlot;

	if (!canAirliftAt(plot(), iX, iY))
	{
		return false;
	}

	pCity = plot()->getPlotCity();
	FAssert(pCity != NULL);
	pTargetPlot = GC.getMapINLINE().plotINLINE(iX, iY);
	FAssert(pTargetPlot != NULL);
	pTargetCity = pTargetPlot->getPlotCity();
	FAssert(pTargetCity != NULL);
	FAssert(pCity != pTargetCity);

	pCity->changeCurrAirlift(1);
	if (pTargetCity->getMaxAirlift() == 0)
	{
		pTargetCity->setAirliftTargeted(true);
	}

	finishMoves();

	setXY(pTargetPlot->getX_INLINE(), pTargetPlot->getY_INLINE());

	return true;
}


bool CvUnit::isNukeVictim(const CvPlot* pPlot, TeamTypes eTeam) const
{
	CvPlot* pLoopPlot;
	int iDX, iDY;

	if (!(GET_TEAM(eTeam).isAlive()))
	{
		return false;
	}

	if (eTeam == getTeam())
	{
		return false;
	}

	for (iDX = -(nukeRange()); iDX <= nukeRange(); iDX++)
	{
		for (iDY = -(nukeRange()); iDY <= nukeRange(); iDY++)
		{
			pLoopPlot	= plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);

			if (pLoopPlot != NULL)
			{
				if (pLoopPlot->getTeam() == eTeam)
				{
					return true;
				}

				if (pLoopPlot->plotCheck(PUF_isCombatTeam, eTeam, getTeam()) != NULL)
				{
					return true;
				}
			}
		}
	}

	return false;
}


bool CvUnit::canNuke(const CvPlot* pPlot) const
{
	if (nukeRange() == -1)
	{
		return false;
	}

	return true;
}


bool CvUnit::canNukeAt(const CvPlot* pPlot, int iX, int iY) const
{
	CvPlot* pTargetPlot;
	int iI;

	if (!canNuke(pPlot))
	{
		return false;
	}

	int iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iX, iY);
	if (iDistance <= nukeRange())
	{
		return false;
	}

	if (airRange() > 0 && iDistance > airRange())
	{
		return false;
	}

	pTargetPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	for (iI = 0; iI < MAX_TEAMS; iI++)
	{
		if (isNukeVictim(pTargetPlot, ((TeamTypes)iI)))
		{
			if (!isEnemy((TeamTypes)iI, pPlot))
			{
				return false;
			}
		}
	}

	return true;
}


bool CvUnit::nuke(int iX, int iY)
{
	CvPlot* pPlot;
	CvWString szBuffer;
	bool abTeamsAffected[MAX_TEAMS];
	TeamTypes eBestTeam;
	int iBestInterception;
	int iI, iJ, iK;

	if (!canNukeAt(plot(), iX, iY))
	{
		return false;
	}

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	for (iI = 0; iI < MAX_TEAMS; iI++)
	{
		abTeamsAffected[iI] = isNukeVictim(pPlot, ((TeamTypes)iI));
	}

	for (iI = 0; iI < MAX_TEAMS; iI++)
	{
		if (abTeamsAffected[iI])
		{
			if (!isEnemy((TeamTypes)iI))
			{
				GET_TEAM(getTeam()).declareWar(((TeamTypes)iI), false, WARPLAN_LIMITED);
			}
		}
	}

	iBestInterception = 0;
	eBestTeam = NO_TEAM;

	for (iI = 0; iI < MAX_TEAMS; iI++)
	{
		if (abTeamsAffected[iI])
		{
			if (GET_TEAM((TeamTypes)iI).getNukeInterception() > iBestInterception)
			{
				iBestInterception = GET_TEAM((TeamTypes)iI).getNukeInterception();
				eBestTeam = ((TeamTypes)iI);
			}
		}
	}

	iBestInterception *= (100 - m_pUnitInfo->getEvasionProbability());
	iBestInterception /= 100;

	setReconPlot(pPlot);

	if (GC.getGameINLINE().getSorenRandNum(100, "Nuke") < iBestInterception)
	{
		for (iI = 0; iI < MAX_PLAYERS; iI++)
		{
			if (GET_PLAYER((PlayerTypes)iI).isAlive())
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_NUKE_INTERCEPTED", GET_PLAYER(getOwnerINLINE()).getNameKey(), getNameKey(), GET_TEAM(eBestTeam).getName().GetCString());
				gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), (((PlayerTypes)iI) == getOwnerINLINE()), GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_NUKE_INTERCEPTED", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
			}
		}

		if (pPlot->isActiveVisible(false))
		{
			// Nuke entity mission
			CvMissionDefinition kDefiniton;
			kDefiniton.setMissionTime(GC.getMissionInfo(MISSION_NUKE).getTime() * gDLL->getSecsPerTurn());
			kDefiniton.setMissionType(MISSION_NUKE);
			kDefiniton.setPlot(pPlot);
			kDefiniton.setUnit(BATTLE_UNIT_ATTACKER, this);
			kDefiniton.setUnit(BATTLE_UNIT_DEFENDER, this);

			// Add the intercepted mission (defender is not NULL)
			gDLL->getEntityIFace()->AddMission(&kDefiniton);
		}

		kill(true);
		return true; // Intercepted!!! (XXX need special event for this...)
	}

	if (pPlot->isActiveVisible(false))
	{
		// Nuke entity mission
		CvMissionDefinition kDefiniton;
		kDefiniton.setMissionTime(GC.getMissionInfo(MISSION_NUKE).getTime() * gDLL->getSecsPerTurn());
		kDefiniton.setMissionType(MISSION_NUKE);
		kDefiniton.setPlot(pPlot);
		kDefiniton.setUnit(BATTLE_UNIT_ATTACKER, this);
		kDefiniton.setUnit(BATTLE_UNIT_DEFENDER, NULL);

		// Add the non-intercepted mission (defender is NULL)
		gDLL->getEntityIFace()->AddMission(&kDefiniton);
	}

	setMadeAttack(true);
	setAttackPlot(pPlot, false);

	for (iI = 0; iI < MAX_TEAMS; iI++)
	{
		if (abTeamsAffected[iI])
		{
			GET_TEAM((TeamTypes)iI).changeWarWeariness(getTeam(), 100 * GC.getDefineINT("WW_HIT_BY_NUKE"));
			GET_TEAM(getTeam()).changeWarWeariness(((TeamTypes)iI), 100 * GC.getDefineINT("WW_ATTACKED_WITH_NUKE"));
			GET_TEAM(getTeam()).AI_changeWarSuccess(((TeamTypes)iI), GC.getDefineINT("WAR_SUCCESS_NUKE"));
		}
	}

	for (iI = 0; iI < MAX_TEAMS; iI++)
	{
		if (GET_TEAM((TeamTypes)iI).isAlive())
		{
			if (iI != getTeam())
			{
				if (abTeamsAffected[iI])
				{
					for (iJ = 0; iJ < MAX_PLAYERS; iJ++)
					{
						if (GET_PLAYER((PlayerTypes)iJ).isAlive())
						{
							if (GET_PLAYER((PlayerTypes)iJ).getTeam() == ((TeamTypes)iI))
							{
								GET_PLAYER((PlayerTypes)iJ).AI_changeMemoryCount(getOwnerINLINE(), MEMORY_NUKED_US, 1);
							}
						}
					}
				}
				else
				{
					for (iJ = 0; iJ < MAX_TEAMS; iJ++)
					{
						if (GET_TEAM((TeamTypes)iJ).isAlive())
						{
							if (abTeamsAffected[iJ])
							{
								if (GET_TEAM((TeamTypes)iI).isHasMet((TeamTypes)iJ))
								{
									if (GET_TEAM((TeamTypes)iI).AI_getAttitude((TeamTypes)iJ) >= ATTITUDE_CAUTIOUS)
									{
										for (iK = 0; iK < MAX_PLAYERS; iK++)
										{
											if (GET_PLAYER((PlayerTypes)iK).isAlive())
											{
												if (GET_PLAYER((PlayerTypes)iK).getTeam() == ((TeamTypes)iI))
												{
													GET_PLAYER((PlayerTypes)iK).AI_changeMemoryCount(getOwnerINLINE(), MEMORY_NUKED_FRIEND, 1);
												}
											}
										}
										break;
									}
								}
							}
						}
					}
				}
			}
		}
	}

	// XXX some AI should declare war here...

	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_NUKE_LAUNCHED", GET_PLAYER(getOwnerINLINE()).getNameKey(), getNameKey());
			gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)iI), (((PlayerTypes)iI) == getOwnerINLINE()), GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_NUKE_EXPLODES", MESSAGE_TYPE_MAJOR_EVENT, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
		}
	}

	if (isSuicide())
	{
		kill(true);
	}

	return true;
}


bool CvUnit::canRecon(const CvPlot* pPlot) const
{
	if (getDomainType() != DOMAIN_AIR)
	{
		return false;
	}

	if (airRange() == 0)
	{
		return false;
	}

	if (m_pUnitInfo->isSuicide())
	{
		return false;
	}

	return true;
}



bool CvUnit::canReconAt(const CvPlot* pPlot, int iX, int iY) const
{
	if (!canRecon(pPlot))
	{
		return false;
	}

	int iDistance = plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iX, iY);
	if (iDistance > airRange() || 0 == iDistance)
	{
		return false;
	}

	return true;
}


bool CvUnit::recon(int iX, int iY)
{
	CvPlot* pPlot;

	if (!canReconAt(plot(), iX, iY))
	{
		return false;
	}

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	setReconPlot(pPlot);

	finishMoves();

	if (pPlot->isActiveVisible(false))
	{
		CvAirMissionDefinition kAirMission;
		kAirMission.setMissionType(MISSION_RECON);
		kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
		kAirMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
		kAirMission.setDamage(BATTLE_UNIT_DEFENDER, 0);
		kAirMission.setDamage(BATTLE_UNIT_ATTACKER, 0);
		kAirMission.setPlot(pPlot);
		kAirMission.setMissionTime(GC.getMissionInfo((MissionTypes)MISSION_RECON).getTime() * gDLL->getSecsPerTurn());
		gDLL->getEntityIFace()->AddMission(&kAirMission);
	}

	return true;
}


bool CvUnit::canParadrop(const CvPlot* pPlot) const
{
	if (getDropRange() <= 0)
	{
		return false;
	}

	if (hasMoved())
	{
		return false;
	}

	if (!pPlot->isFriendlyCity(*this, true))
	{
		return false;
	}

	return true;
}



bool CvUnit::canParadropAt(const CvPlot* pPlot, int iX, int iY) const
{
	if (!canParadrop(pPlot))
	{
		return false;
	}

	CvPlot* pTargetPlot = GC.getMapINLINE().plotINLINE(iX, iY);
	if (NULL == pTargetPlot || pTargetPlot == pPlot)
	{
		return false;
	}

	if (!pTargetPlot->isVisible(getTeam(), false))
	{
		return false;
	}

	if (!canMoveInto(pTargetPlot, false, false, true))
	{
		return false;
	}

	if (plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iX, iY) > getDropRange())
	{
		return false;
	}

	if (!canCoexistWithEnemyUnit(NO_TEAM))
	{
		if (pTargetPlot->isEnemyCity(*this))
		{
			return false;
		}

		if (pTargetPlot->isVisibleEnemyUnit(this))
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::paradrop(int iX, int iY)
{
	if (!canParadropAt(plot(), iX, iY))
	{
		return false;
	}

	CvPlot* pPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	changeMoves(GC.getMOVE_DENOMINATOR() / 2);
	setMadeAttack(true);

	setXY(pPlot->getX_INLINE(), pPlot->getY_INLINE());

	//check if intercepted
	if(interceptTest(pPlot))
	{
		return true;
	}

	//play paradrop animation by itself
	if (pPlot->isActiveVisible(false))
	{
		CvAirMissionDefinition kAirMission;
		kAirMission.setMissionType(MISSION_PARADROP);
		kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
		kAirMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
		kAirMission.setDamage(BATTLE_UNIT_DEFENDER, 0);
		kAirMission.setDamage(BATTLE_UNIT_ATTACKER, 0);
		kAirMission.setPlot(pPlot);
		kAirMission.setMissionTime(GC.getMissionInfo((MissionTypes)MISSION_PARADROP).getTime() * gDLL->getSecsPerTurn());
		gDLL->getEntityIFace()->AddMission(&kAirMission);
	}

	return true;
}


bool CvUnit::canAirBomb(const CvPlot* pPlot) const
{
	if (getDomainType() != DOMAIN_AIR)
	{
		return false;
	}

	if (airBombBaseRate() == 0)
	{
		return false;
	}

	if (isMadeAttack())
	{
		return false;
	}

	return true;
}


bool CvUnit::canAirBombAt(const CvPlot* pPlot, int iX, int iY) const
{
	CvCity* pCity;
	CvPlot* pTargetPlot;

	if (!canAirBomb(pPlot))
	{
		return false;
	}

	pTargetPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	if (plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pTargetPlot->getX_INLINE(), pTargetPlot->getY_INLINE()) > airRange())
	{
		return false;
	}

	if (pTargetPlot->isOwned())
	{
		if (!potentialWarAction(pTargetPlot))
		{
			return false;
		}
	}

	pCity = pTargetPlot->getPlotCity();

	if (pCity != NULL)
	{
		if (!(pCity->isBombardable(this)))
		{
			return false;
		}
	}
	else
	{
		if (pTargetPlot->getImprovementType() == NO_IMPROVEMENT)
		{
			return false;
		}

		if (GC.getImprovementInfo(pTargetPlot->getImprovementType()).isPermanent())
		{
			return false;
		}

		if (GC.getImprovementInfo(pTargetPlot->getImprovementType()).getAirBombDefense() == -1)
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::airBomb(int iX, int iY)
{
	CvCity* pCity;
	CvPlot* pPlot;
	CvWString szBuffer;

	if (!canAirBombAt(plot(), iX, iY))
	{
		return false;
	}

	pPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	if (!isEnemy(pPlot->getTeam()))
	{
		getGroup()->groupDeclareWar(pPlot, true);
	}

	if (!isEnemy(pPlot->getTeam()))
	{
		return false;
	}

	if (interceptTest(pPlot))
	{
		return true;
	}

	pCity = pPlot->getPlotCity();

	if (pCity != NULL)
	{
		pCity->changeDefenseModifier(-airBombCurrRate());

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_DEFENSES_REDUCED_TO", pCity->getNameKey(), pCity->getDefenseModifier(false), getNameKey());
		gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BOMBARDED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE(), true, true);

		szBuffer = gDLL->getText("TXT_KEY_MISC_ENEMY_DEFENSES_REDUCED_TO", getNameKey(), pCity->getNameKey(), pCity->getDefenseModifier(false));
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BOMBARD", MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pCity->getX_INLINE(), pCity->getY_INLINE());
	}
	else
	{
		if (pPlot->getImprovementType() != NO_IMPROVEMENT)
		{
			if (GC.getGameINLINE().getSorenRandNum(airBombCurrRate(), "Air Bomb - Offense") >=
					GC.getGameINLINE().getSorenRandNum(GC.getImprovementInfo(pPlot->getImprovementType()).getAirBombDefense(), "Air Bomb - Defense"))
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_DESTROYED_IMP", getNameKey(), GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide());
				gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

				if (pPlot->isOwned())
				{
					szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_IMP_WAS_DESTROYED", GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide(), getNameKey(), getVisualCivAdjective(pPlot->getTeam()));
					gDLL->getInterfaceIFace()->addMessage(pPlot->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
				}

				pPlot->setImprovementType((ImprovementTypes)(GC.getImprovementInfo(pPlot->getImprovementType()).getImprovementPillage()));
			}
			else
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_UNIT_FAIL_DESTROY_IMP", getNameKey(), GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide());
				gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BOMB_FAILS", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
			}
		}
	}

	setReconPlot(pPlot);

	setMadeAttack(true);
	changeMoves(GC.getMOVE_DENOMINATOR());

	if (pPlot->isActiveVisible(false))
	{
		CvAirMissionDefinition kAirMission;
		kAirMission.setMissionType(MISSION_AIRBOMB);
		kAirMission.setUnit(BATTLE_UNIT_ATTACKER, this);
		kAirMission.setUnit(BATTLE_UNIT_DEFENDER, NULL);
		kAirMission.setDamage(BATTLE_UNIT_DEFENDER, 0);
		kAirMission.setDamage(BATTLE_UNIT_ATTACKER, 0);
		kAirMission.setPlot(pPlot);
		kAirMission.setMissionTime(GC.getMissionInfo((MissionTypes)MISSION_AIRBOMB).getTime() * gDLL->getSecsPerTurn());

		gDLL->getEntityIFace()->AddMission(&kAirMission);
	}

	if (isSuicide())
	{
		kill(true);
	}

	return true;
}


CvCity* CvUnit::bombardTarget(const CvPlot* pPlot) const
{
	int iBestValue = MAX_INT;
	CvCity* pBestCity = NULL;

	for (int iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		CvPlot* pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));

		if (pLoopPlot != NULL)
		{
			CvCity* pLoopCity = pLoopPlot->getPlotCity();

			if (pLoopCity != NULL)
			{
				if (pLoopCity->isBombardable(this))
				{
					int iValue = pLoopCity->getDefenseDamage();

					// always prefer cities we are at war with
					if (isEnemy(pLoopCity->getTeam(), pPlot))
					{
						iValue *= 128;
					}

					if (iValue < iBestValue)
					{
						iBestValue = iValue;
						pBestCity = pLoopCity;
					}
				}
			}
		}
	}

	return pBestCity;
}


bool CvUnit::canBombard(const CvPlot* pPlot) const
{
	if (bombardRate() <= 0)
	{
		return false;
	}

	if (isMadeAttack())
	{
		return false;
	}

	if (isCargo())
	{
		return false;
	}

	if (bombardTarget(pPlot) == NULL)
	{
		return false;
	}

	return true;
}


bool CvUnit::bombard()
{
	CvPlot* pPlot = plot();
	if (!canBombard(pPlot))
	{
		return false;
	}

	CvCity* pBombardCity = bombardTarget(pPlot);
	FAssertMsg(pBombardCity != NULL, "BombardCity is not assigned a valid value");

	CvPlot* pTargetPlot = pBombardCity->plot();
	if (!isEnemy(pTargetPlot->getTeam()))
	{
		getGroup()->groupDeclareWar(pTargetPlot, true);
	}

	if (!isEnemy(pTargetPlot->getTeam()))
	{
		return false;
	}

	int iBombardModifier = 0;
	if (!ignoreBuildingDefense())
	{
		iBombardModifier -= pBombardCity->getBuildingBombardDefense();
	}

	pBombardCity->changeDefenseModifier(-(bombardRate() * std::max(0, 100 + iBombardModifier)) / 100);

	setMadeAttack(true);
	changeMoves(GC.getMOVE_DENOMINATOR());

	CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_DEFENSES_IN_CITY_REDUCED_TO", pBombardCity->getNameKey(), pBombardCity->getDefenseModifier(false), GET_PLAYER(getOwnerINLINE()).getNameKey());
	gDLL->getInterfaceIFace()->addMessage(pBombardCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BOMBARDED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pBombardCity->getX_INLINE(), pBombardCity->getY_INLINE(), true, true);

	szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_REDUCE_CITY_DEFENSES", getNameKey(), pBombardCity->getNameKey(), pBombardCity->getDefenseModifier(false));
	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BOMBARD", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pBombardCity->getX_INLINE(), pBombardCity->getY_INLINE());

	if (pPlot->isActiveVisible(false))
	{
		CvUnit *pDefender = pBombardCity->plot()->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

		// Bombard entity mission
		CvMissionDefinition kDefiniton;
		kDefiniton.setMissionTime(GC.getMissionInfo(MISSION_BOMBARD).getTime() * gDLL->getSecsPerTurn());
		kDefiniton.setMissionType(MISSION_BOMBARD);
		kDefiniton.setPlot(pBombardCity->plot());
		kDefiniton.setUnit(BATTLE_UNIT_ATTACKER, this);
		kDefiniton.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
		gDLL->getEntityIFace()->AddMission(&kDefiniton);
	}

//FfH: Added by Kael 08/30/2007
    if (isSuicide())
    {
        kill(true);
    }
//FfH: End Add

	return true;
}


bool CvUnit::canPillage(const CvPlot* pPlot) const
{
/*************************************************************************************************/
/**	PillageToggle (PromotionInfos)	05/15/08										Xienwolf	**/
/**																								**/
/**							Blocks or Simulates the UnitInfo Flag								**/
/*************************************************************************************************/
/**								---- Start Original Code ----
	if (!(m_pUnitInfo->isPillage()))
								----  End Original Code  ----									**/
    if (isCannotPillage())
    {
        return false;
    }
	if (!(m_pUnitInfo->isPillage() || isCanPillage()))
/*************************************************************************************************/
/**	PillageToggle (PromotionInfos)				END												**/
/*************************************************************************************************/
	{
		return false;
	}

	if (pPlot->isCity())
	{
		return false;
	}

	if (pPlot->getImprovementType() == NO_IMPROVEMENT)
	{
		if (!(pPlot->isRoute()))
		{
			return false;
		}
	}
	else
	{
		if (GC.getImprovementInfo(pPlot->getImprovementType()).isPermanent())
		{
			return false;
		}
	}

	if (pPlot->isOwned())
	{
		if (!potentialWarAction(pPlot))
		{
			if ((pPlot->getImprovementType() == NO_IMPROVEMENT) || (pPlot->getOwnerINLINE() != getOwnerINLINE()))
			{
				return false;
			}
		}
	}

	if (!(pPlot->isValidDomainForAction(*this)))
	{
		return false;
	}

	return true;
}


bool CvUnit::pillage()
{
	CvWString szBuffer;
	int iPillageGold;
	long lPillageGold;
	ImprovementTypes eTempImprovement = NO_IMPROVEMENT;
	RouteTypes eTempRoute = NO_ROUTE;

	CvPlot* pPlot = plot();

	if (!canPillage(pPlot))
	{
		return false;
	}

	if (pPlot->isOwned())
	{
		// we should not be calling this without declaring war first, so do not declare war here
		if (!isEnemy(pPlot->getTeam(), pPlot))
		{
			if ((pPlot->getImprovementType() == NO_IMPROVEMENT) || (pPlot->getOwnerINLINE() != getOwnerINLINE()))
			{
				return false;
			}
		}
	}

	if (pPlot->isWater())
	{
		CvUnit* pInterceptor = bestSeaPillageInterceptor(pPlot);
		if (NULL != pInterceptor)
		{
			setMadeAttack(false);

			attack(pInterceptor->plot(), false);

			return false;
		}
	}

	if (pPlot->getImprovementType() != NO_IMPROVEMENT)
	{
		eTempImprovement = pPlot->getImprovementType();

		if (pPlot->getTeam() != getTeam())
		{
			// Use python to determine pillage amounts...
			lPillageGold = 0;

			CyPlot* pyPlot = new CyPlot(pPlot);
			CyUnit* pyUnit = new CyUnit(this);

			CyArgsList argsList;
			argsList.add(gDLL->getPythonIFace()->makePythonObject(pyPlot));	// pass in plot class
			argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class

			gDLL->getPythonIFace()->callFunction(PYGameModule, "doPillageGold", argsList.makeFunctionArgs(),&lPillageGold);

			delete pyPlot;	// python fxn must not hold on to this pointer
			delete pyUnit;	// python fxn must not hold on to this pointer

			iPillageGold = (int)lPillageGold;

			if (iPillageGold > 0)
			{
//WH: added by Ploeperpengel 04/23/2008---- BEGIN InfluenceDrivenWar -----by Moctezuma---
				float fInfluenceRatio = 0.0f;
				if (GC.getDefineINT("IDW_ENABLED") && GC.getDefineINT("IDW_PILLAGE_INFLUENCE_ENABLED"))
				{
					if (atWar(pPlot->getTeam(), getTeam()))
					{
						fInfluenceRatio = doPillageInfluence();
					}
				}
// ------ END InfluenceDrivenWar -------------------------------

//FfH Traits: Added by Kale 08/02/2007
                iPillageGold += (iPillageGold * GET_PLAYER(getOwnerINLINE()).getPillagingGold()) / 100;
//FfH: End Add

				GET_PLAYER(getOwnerINLINE()).changeGold(iPillageGold);

				szBuffer = gDLL->getText("TXT_KEY_MISC_PLUNDERED_GOLD_FROM_IMP", iPillageGold, GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide());

//WH: added by Ploeperpengel 04/23/2008---- BEGIN InfluenceDrivenWar -----by Moctezuma---
				if (fInfluenceRatio > 0.0f)
				{
					CvWString szInfluence;
					szInfluence.Format(L" Tile influence: +%.1f%%", fInfluenceRatio);
					szBuffer += szInfluence;
				}
// ------ END InfluenceDrivenWar -------------------------------

				gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

				if (pPlot->isOwned())
				{
					szBuffer = gDLL->getText("TXT_KEY_MISC_IMP_DESTROYED", GC.getImprovementInfo(pPlot->getImprovementType()).getTextKeyWide(), getNameKey(), getVisualCivAdjective(pPlot->getTeam()));

//WH: added by Ploeperpengel 04/23/2008---- BEGIN InfluenceDrivenWar -----by Moctezuma---
					if (fInfluenceRatio > 0.0f)
					{
						CvWString szInfluence;
						szInfluence.Format(L" Tile influence: -%.1f%%", fInfluenceRatio);
						szBuffer += szInfluence;
					}
// ------ END InfluenceDrivenWar -------------------------------

					gDLL->getInterfaceIFace()->addMessage(pPlot->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
				}
			}
		}

		pPlot->setImprovementType((ImprovementTypes)(GC.getImprovementInfo(pPlot->getImprovementType()).getImprovementPillage()));
	}
	else if (pPlot->isRoute())
	{
		eTempRoute = pPlot->getRouteType();
		pPlot->setRouteType(NO_ROUTE, true); // XXX downgrade rail???
	}

	changeMoves(GC.getMOVE_DENOMINATOR());

	if (pPlot->isActiveVisible(false))
	{
		// Pillage entity mission
		CvMissionDefinition kDefiniton;
		kDefiniton.setMissionTime(GC.getMissionInfo(MISSION_PILLAGE).getTime() * gDLL->getSecsPerTurn());
		kDefiniton.setMissionType(MISSION_PILLAGE);
		kDefiniton.setPlot(pPlot);
		kDefiniton.setUnit(BATTLE_UNIT_ATTACKER, this);
		kDefiniton.setUnit(BATTLE_UNIT_DEFENDER, NULL);
		gDLL->getEntityIFace()->AddMission(&kDefiniton);
	}

	if (eTempImprovement != NO_IMPROVEMENT || eTempRoute != NO_ROUTE)
	{
		gDLL->getEventReporterIFace()->unitPillage(this, eTempImprovement, eTempRoute, getOwnerINLINE());
	}

	return true;
}


bool CvUnit::canPlunder(const CvPlot* pPlot, bool bTestVisible) const
{
	if (getDomainType() != DOMAIN_SEA)
	{
		return false;
	}

	if (!(m_pUnitInfo->isPillage()))
	{
		return false;
	}

	if (!pPlot->isWater())
	{
		return false;
	}

	if (pPlot->isFreshWater())
	{
		return false;
	}

	if (!pPlot->isValidDomainForAction(*this))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (pPlot->getTeam() == getTeam())
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::plunder()
{
	CvPlot* pPlot = plot();

	if (!canPlunder(pPlot))
	{
		return false;
	}

	setBlockading(true);

	finishMoves();

	return true;
}


void CvUnit::updatePlunder(int iChange, bool bUpdatePlotGroups)
{
	int iBlockadeRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE");

	bool bOldTradeNet;
	bool bChanged = false;

	for (int iTeam = 0; iTeam < MAX_TEAMS; ++iTeam)
	{
		if (isEnemy((TeamTypes)iTeam))
		{
			for (int i = -iBlockadeRange; i <= iBlockadeRange; ++i)
			{
				for (int j = -iBlockadeRange; j <= iBlockadeRange; ++j)
				{
					CvPlot* pLoopPlot = ::plotXY(getX_INLINE(), getY_INLINE(), i, j);

					if (NULL != pLoopPlot && pLoopPlot->isWater() && pLoopPlot->area() == area())
					{
						if (!bChanged)
						{
							bOldTradeNet = pLoopPlot->isTradeNetwork((TeamTypes)iTeam);
						}

						pLoopPlot->changeBlockadedCount((TeamTypes)iTeam, iChange);

						if (!bChanged)
						{
							bChanged = (bOldTradeNet != pLoopPlot->isTradeNetwork((TeamTypes)iTeam));
						}
					}
				}
			}
		}
	}

	if (bChanged)
	{
		gDLL->getInterfaceIFace()->setDirty(BlockadedPlots_DIRTY_BIT, true);

		if (bUpdatePlotGroups)
		{
			GC.getGameINLINE().updatePlotGroups();
		}
	}
}


int CvUnit::sabotageCost(const CvPlot* pPlot) const
{
	return GC.getDefineINT("BASE_SPY_SABOTAGE_COST");
}


// XXX compare with destroy prob...
int CvUnit::sabotageProb(const CvPlot* pPlot, ProbabilityTypes eProbStyle) const
{
	CvPlot* pLoopPlot;
	int iDefenseCount;
	int iCounterSpyCount;
	int iProb;
	int iI;

	iProb = 0; // XXX

	if (pPlot->isOwned())
	{
		iDefenseCount = pPlot->plotCount(PUF_canDefend, -1, -1, NO_PLAYER, pPlot->getTeam());
		iCounterSpyCount = pPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());

		for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
		{
			pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));

			if (pLoopPlot != NULL)
			{
				iCounterSpyCount += pLoopPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());
			}
		}
	}
	else
	{
		iDefenseCount = 0;
		iCounterSpyCount = 0;
	}

	if (eProbStyle == PROBABILITY_HIGH)
	{
		iCounterSpyCount = 0;
	}

	iProb += (40 / (iDefenseCount + 1)); // XXX

	if (eProbStyle != PROBABILITY_LOW)
	{
		iProb += (50 / (iCounterSpyCount + 1)); // XXX
	}

	return iProb;
}


bool CvUnit::canSabotage(const CvPlot* pPlot, bool bTestVisible) const
{
	if (!(m_pUnitInfo->isSabotage()))
	{
		return false;
	}

	if (pPlot->getTeam() == getTeam())
	{
		return false;
	}

	if (pPlot->isCity())
	{
		return false;
	}

	if (pPlot->getImprovementType() == NO_IMPROVEMENT)
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (GET_PLAYER(getOwnerINLINE()).getGold() < sabotageCost(pPlot))
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::sabotage()
{
	CvCity* pNearestCity;
	CvPlot* pPlot;
	CvWString szBuffer;
	bool bCaught;

	if (!canSabotage(plot()))
	{
		return false;
	}

	pPlot = plot();

	bCaught = (GC.getGameINLINE().getSorenRandNum(100, "Spy: Sabotage") > sabotageProb(pPlot));

	GET_PLAYER(getOwnerINLINE()).changeGold(-(sabotageCost(pPlot)));

	if (!bCaught)
	{
		pPlot->setImprovementType((ImprovementTypes)(GC.getImprovementInfo(pPlot->getImprovementType()).getImprovementPillage()));

		finishMoves();

		pNearestCity = GC.getMapINLINE().findCity(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pPlot->getOwnerINLINE(), NO_TEAM, false);

		if (pNearestCity != NULL)
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_SPY_SABOTAGED", getNameKey(), pNearestCity->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_SABOTAGE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

			if (pPlot->isOwned())
			{
				szBuffer = gDLL->getText("TXT_KEY_MISC_SABOTAGE_NEAR", pNearestCity->getNameKey());
				gDLL->getInterfaceIFace()->addMessage(pPlot->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_SABOTAGE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);
			}
		}

		if (pPlot->isActiveVisible(false))
		{
			NotifyEntity(MISSION_SABOTAGE);
		}
	}
	else
	{
		if (pPlot->isOwned())
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_SPY_CAUGHT_AND_KILLED", GET_PLAYER(getOwnerINLINE()).getCivilizationAdjective(), getNameKey());
			gDLL->getInterfaceIFace()->addMessage(pPlot->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSE", MESSAGE_TYPE_INFO);
		}

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_SPY_CAUGHT", getNameKey());
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSED", MESSAGE_TYPE_INFO);

		if (plot()->isActiveVisible(false))
		{
			NotifyEntity(MISSION_SURRENDER);
		}

		if (pPlot->isOwned())
		{
			if (!isEnemy(pPlot->getTeam(), pPlot))
			{
				GET_PLAYER(pPlot->getOwnerINLINE()).AI_changeMemoryCount(getOwnerINLINE(), MEMORY_SPY_CAUGHT, 1);
			}
		}

		kill(true, pPlot->getOwnerINLINE());
	}

	return true;
}


int CvUnit::destroyCost(const CvPlot* pPlot) const
{
	CvCity* pCity;
	bool bLimited;

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return 0;
	}

	bLimited = false;

	if (pCity->isProductionUnit())
	{
		bLimited = isLimitedUnitClass((UnitClassTypes)(GC.getUnitInfo(pCity->getProductionUnit()).getUnitClassType()));
	}
	else if (pCity->isProductionBuilding())
	{
		bLimited = isLimitedWonderClass((BuildingClassTypes)(GC.getBuildingInfo(pCity->getProductionBuilding()).getBuildingClassType()));
	}
	else if (pCity->isProductionProject())
	{
		bLimited = isLimitedProject(pCity->getProductionProject());
	}

	return (GC.getDefineINT("BASE_SPY_DESTROY_COST") + (pCity->getProduction() * ((bLimited) ? GC.getDefineINT("SPY_DESTROY_COST_MULTIPLIER_LIMITED") : GC.getDefineINT("SPY_DESTROY_COST_MULTIPLIER"))));
}


int CvUnit::destroyProb(const CvPlot* pPlot, ProbabilityTypes eProbStyle) const
{
	CvCity* pCity;
	CvPlot* pLoopPlot;
	int iDefenseCount;
	int iCounterSpyCount;
	int iProb;
	int iI;

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return 0;
	}

	iProb = 0; // XXX

	iDefenseCount = pPlot->plotCount(PUF_canDefend, -1, -1, NO_PLAYER, pPlot->getTeam());

	iCounterSpyCount = pPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));

		if (pLoopPlot != NULL)
		{
			iCounterSpyCount += pLoopPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());
		}
	}

	if (eProbStyle == PROBABILITY_HIGH)
	{
		iCounterSpyCount = 0;
	}

	iProb += (25 / (iDefenseCount + 1)); // XXX

	if (eProbStyle != PROBABILITY_LOW)
	{
		iProb += (50 / (iCounterSpyCount + 1)); // XXX
	}

	iProb += std::min(25, pCity->getProductionTurnsLeft()); // XXX

	return iProb;
}


bool CvUnit::canDestroy(const CvPlot* pPlot, bool bTestVisible) const
{
	CvCity* pCity;

	if (!(m_pUnitInfo->isDestroy()))
	{
		return false;
	}

	if (pPlot->getTeam() == getTeam())
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getProduction() == 0)
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (GET_PLAYER(getOwnerINLINE()).getGold() < destroyCost(pPlot))
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::destroy()
{
	CvCity* pCity;
	CvWString szBuffer;
	bool bCaught;

	if (!canDestroy(plot()))
	{
		return false;
	}

	bCaught = (GC.getGameINLINE().getSorenRandNum(100, "Spy: Destroy") > destroyProb(plot()));

	pCity = plot()->getPlotCity();
	FAssertMsg(pCity != NULL, "City is not assigned a valid value");

	GET_PLAYER(getOwnerINLINE()).changeGold(-(destroyCost(plot())));

	if (!bCaught)
	{
		pCity->setProduction(pCity->getProduction() / 2);

		finishMoves();

		szBuffer = gDLL->getText("TXT_KEY_MISC_SPY_DESTROYED_PRODUCTION", getNameKey(), pCity->getProductionNameKey(), pCity->getNameKey());
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DESTROY", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pCity->getX_INLINE(), pCity->getY_INLINE());

		szBuffer = gDLL->getText("TXT_KEY_MISC_CITY_PRODUCTION_DESTROYED", pCity->getProductionNameKey(), pCity->getNameKey());
		gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DESTROY", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE(), true, true);

		if (plot()->isActiveVisible(false))
		{
			NotifyEntity(MISSION_DESTROY);
		}
	}
	else
	{
		szBuffer = gDLL->getText("TXT_KEY_MISC_SPY_CAUGHT_AND_KILLED", GET_PLAYER(getOwnerINLINE()).getCivilizationAdjective(), getNameKey());
		gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSE", MESSAGE_TYPE_INFO);

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_SPY_CAUGHT", getNameKey());
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSED", MESSAGE_TYPE_INFO);

		if (plot()->isActiveVisible(false))
		{
			NotifyEntity(MISSION_SURRENDER);
		}

		if (!isEnemy(pCity->getTeam()))
		{
			GET_PLAYER(pCity->getOwnerINLINE()).AI_changeMemoryCount(getOwnerINLINE(), MEMORY_SPY_CAUGHT, 1);
		}

		kill(true, pCity->getOwnerINLINE());
	}

	return true;
}


int CvUnit::stealPlansCost(const CvPlot* pPlot) const
{
	CvCity* pCity;

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return 0;
	}

	return (GC.getDefineINT("BASE_SPY_STEAL_PLANS_COST") + ((GET_TEAM(pCity->getTeam()).getTotalLand() + GET_TEAM(pCity->getTeam()).getTotalPopulation()) * GC.getDefineINT("SPY_STEAL_PLANS_COST_MULTIPLIER")));
}


// XXX compare with destroy prob...
int CvUnit::stealPlansProb(const CvPlot* pPlot, ProbabilityTypes eProbStyle) const
{
	CvCity* pCity;
	CvPlot* pLoopPlot;
	int iDefenseCount;
	int iCounterSpyCount;
	int iProb;
	int iI;

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return 0;
	}

	iProb = ((pCity->isGovernmentCenter()) ? 20 : 0); // XXX

	iDefenseCount = pPlot->plotCount(PUF_canDefend, -1, -1, NO_PLAYER, pPlot->getTeam());

	iCounterSpyCount = pPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());

	for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
	{
		pLoopPlot = plotDirection(pPlot->getX_INLINE(), pPlot->getY_INLINE(), ((DirectionTypes)iI));

		if (pLoopPlot != NULL)
		{
			iCounterSpyCount += pLoopPlot->plotCount(PUF_isCounterSpy, -1, -1, NO_PLAYER, pPlot->getTeam());
		}
	}

	if (eProbStyle == PROBABILITY_HIGH)
	{
		iCounterSpyCount = 0;
	}

	iProb += (20 / (iDefenseCount + 1)); // XXX

	if (eProbStyle != PROBABILITY_LOW)
	{
		iProb += (50 / (iCounterSpyCount + 1)); // XXX
	}

	return iProb;
}


bool CvUnit::canStealPlans(const CvPlot* pPlot, bool bTestVisible) const
{
	CvCity* pCity;

	if (!(m_pUnitInfo->isStealPlans()))
	{
		return false;
	}

	if (pPlot->getTeam() == getTeam())
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (GET_PLAYER(getOwnerINLINE()).getGold() < stealPlansCost(pPlot))
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::stealPlans()
{
	CvCity* pCity;
	CvWString szBuffer;
	bool bCaught;

	if (!canStealPlans(plot()))
	{
		return false;
	}

	bCaught = (GC.getGameINLINE().getSorenRandNum(100, "Spy: Steal Plans") > stealPlansProb(plot()));

	pCity = plot()->getPlotCity();
	FAssertMsg(pCity != NULL, "City is not assigned a valid value");

	GET_PLAYER(getOwnerINLINE()).changeGold(-(stealPlansCost(plot())));

	if (!bCaught)
	{
		GET_TEAM(getTeam()).changeStolenVisibilityTimer(pCity->getTeam(), 2);

		finishMoves();

		szBuffer = gDLL->getText("TXT_KEY_MISC_SPY_STOLE_PLANS", getNameKey(), pCity->getNameKey());
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_STEALPLANS", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pCity->getX_INLINE(), pCity->getY_INLINE());

		szBuffer = gDLL->getText("TXT_KEY_MISC_PLANS_STOLEN", pCity->getNameKey());
		gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_STEALPLANS", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE(), true, true);

		if (plot()->isActiveVisible(false))
		{
			NotifyEntity(MISSION_STEAL_PLANS);
		}
	}
	else
	{
		szBuffer = gDLL->getText("TXT_KEY_MISC_SPY_CAUGHT_AND_KILLED", GET_PLAYER(getOwnerINLINE()).getCivilizationAdjective(), getNameKey());
		gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSE", MESSAGE_TYPE_INFO);

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_SPY_CAUGHT", getNameKey());
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSED", MESSAGE_TYPE_INFO);

		if (plot()->isActiveVisible(false))
		{
			NotifyEntity(MISSION_SURRENDER);
		}

		if (!isEnemy(pCity->getTeam()))
		{
			GET_PLAYER(pCity->getOwnerINLINE()).AI_changeMemoryCount(getOwnerINLINE(), MEMORY_SPY_CAUGHT, 1);
		}

		kill(true, pCity->getOwnerINLINE());
	}

	return true;
}


bool CvUnit::canFound(const CvPlot* pPlot, bool bTestVisible) const
{
	if (!isFound())
	{
		return false;
	}

	if (!(GET_PLAYER(getOwnerINLINE()).canFound(pPlot->getX_INLINE(), pPlot->getY_INLINE(), bTestVisible)))
	{
		return false;
	}

	return true;
}


bool CvUnit::found()
{
	if (!canFound(plot()))
	{
		return false;
	}

	if (GC.getGameINLINE().getActivePlayer() == getOwnerINLINE())
	{
		gDLL->getInterfaceIFace()->lookAt(plot()->getPoint(), CAMERALOOKAT_NORMAL);
	}

	GET_PLAYER(getOwnerINLINE()).found(getX_INLINE(), getY_INLINE());

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_FOUND);
	}

	kill(true);

	return true;
}


bool CvUnit::canSpread(const CvPlot* pPlot, ReligionTypes eReligion, bool bTestVisible) const
{
	CvCity* pCity;

	if (GC.getUSE_USE_CANNOT_SPREAD_RELIGION_CALLBACK())
	{
		CyArgsList argsList;
		argsList.add(getOwner());
		argsList.add(getID());
		argsList.add((int) eReligion);
		argsList.add(pPlot->getX());
		argsList.add(pPlot->getY());
		long lResult=0;
		gDLL->getPythonIFace()->callFunction(PYGameModule, "cannotSpreadReligion", argsList.makeFunctionArgs(), &lResult);
		if (lResult > 0)
		{
			return false;
		}
	}

	if (eReligion == NO_RELIGION)
	{
		return false;
	}

	if (m_pUnitInfo->getReligionSpreads(eReligion) <= 0)
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->isHasReligion(eReligion))
	{
		return false;
	}

	if (!canEnterArea(pPlot->getTeam(), pPlot->area()))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (pCity->getTeam() != getTeam())
		{
			if (GET_PLAYER(pCity->getOwnerINLINE()).isNoNonStateReligionSpread())
			{
				if (eReligion != GET_PLAYER(pCity->getOwnerINLINE()).getStateReligion())
				{
					return false;
				}
			}
		}
	}

	return true;
}


bool CvUnit::spread(ReligionTypes eReligion)
{
	CvCity* pCity;
	CvWString szBuffer;
	int iSpreadProb;

	if (!canSpread(plot(), eReligion))
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		iSpreadProb = m_pUnitInfo->getReligionSpreads(eReligion);

		if (pCity->getTeam() != getTeam())
		{
			iSpreadProb /= 2;
		}

		bool bSuccess;

		iSpreadProb += (((GC.getNumReligionInfos() - pCity->getReligionCount()) * (100 - iSpreadProb)) / GC.getNumReligionInfos());

		if (GC.getGameINLINE().getSorenRandNum(100, "Unit Spread Religion") < iSpreadProb)
		{
			pCity->setHasReligion(eReligion, true, true, false);
			bSuccess = true;
		}
		else
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_RELIGION_FAILED_TO_SPREAD", getNameKey(), GC.getReligionInfo(eReligion).getChar(), pCity->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_NOSPREAD", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE());
			bSuccess = false;
		}

		// Python Event
		gDLL->getEventReporterIFace()->unitSpreadReligionAttempt(this, eReligion, bSuccess);
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_SPREAD);
	}

	kill(true);

	return true;
}


bool CvUnit::canSpreadCorporation(const CvPlot* pPlot, CorporationTypes eCorporation, bool bTestVisible) const
{
	if (NO_CORPORATION == eCorporation)
	{
		return false;
	}

	if (!GET_PLAYER(getOwnerINLINE()).isActiveCorporation(eCorporation))
	{
		return false;
	}

	if (m_pUnitInfo->getCorporationSpreads(eCorporation) <= 0)
	{
		return false;
	}

	CvCity* pCity = pPlot->getPlotCity();

	if (NULL == pCity)
	{
		return false;
	}

	if (pCity->isHasCorporation(eCorporation))
	{
		return false;
	}

	if (!canEnterArea(pPlot->getTeam(), pPlot->area()))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (!GET_PLAYER(pCity->getOwnerINLINE()).isActiveCorporation(eCorporation))
		{
			return false;
		}

		for (int iCorporation = 0; iCorporation < GC.getNumCorporationInfos(); ++iCorporation)
		{
			if (pCity->isHeadquarters((CorporationTypes)iCorporation))
			{
				if (GC.getGameINLINE().isCompetingCorporation((CorporationTypes)iCorporation, eCorporation))
				{
					return false;
				}
			}
		}

		bool bValid = false;

//FfH: Added by Kael 10/21/2007 (So that corporations can be made to not require bonuses)
        if (GC.getCorporationInfo(eCorporation).getPrereqBonus(0) == NO_BONUS)
        {
            bValid = true;
        }
//FfH: End Add

		for (int i = 0; i < GC.getNUM_CORPORATION_PREREQ_BONUSES(); ++i)
		{
			BonusTypes eBonus = (BonusTypes)GC.getCorporationInfo(eCorporation).getPrereqBonus(i);
			if (NO_BONUS != eBonus)
			{
				if (pCity->hasBonus(eBonus))
				{
					bValid = true;
					break;
				}
			}
		}

		if (!bValid)
		{
			return false;
		}

		if (GET_PLAYER(getOwnerINLINE()).getGold() < spreadCorporationCost(eCorporation, pCity))
		{
			return false;
		}
	}

	return true;
}

int CvUnit::spreadCorporationCost(CorporationTypes eCorporation, CvCity* pCity) const
{
	int iCost = std::max(0, GC.getCorporationInfo(eCorporation).getSpreadCost() * (100 + GET_PLAYER(getOwnerINLINE()).calculateInflationRate()));
	iCost /= 100;

	if (NULL != pCity)
	{
		if (getTeam() != pCity->getTeam() && !GET_TEAM(pCity->getTeam()).isVassal(getTeam()))
		{
			iCost *= GC.getDefineINT("CORPORATION_FOREIGN_SPREAD_COST_PERCENT");
			iCost /= 100;
		}

		for (int iCorp = 0; iCorp < GC.getNumCorporationInfos(); ++iCorp)
		{
			if (iCorp != eCorporation)
			{
				if (pCity->isActiveCorporation((CorporationTypes)iCorp))
				{
					if (GC.getGameINLINE().isCompetingCorporation(eCorporation, (CorporationTypes)iCorp))
					{
						iCost *= 100 + GC.getCorporationInfo((CorporationTypes)iCorp).getSpreadFactor();
						iCost /= 100;
					}
				}
			}
		}
	}

	return iCost;
}

bool CvUnit::spreadCorporation(CorporationTypes eCorporation)
{
	int iSpreadProb;

	if (!canSpreadCorporation(plot(), eCorporation))
	{
		return false;
	}

	CvCity* pCity = plot()->getPlotCity();

	if (NULL != pCity)
	{
		GET_PLAYER(getOwnerINLINE()).changeGold(-spreadCorporationCost(eCorporation, pCity));

		iSpreadProb = m_pUnitInfo->getCorporationSpreads(eCorporation);

		if (pCity->getTeam() != getTeam())
		{
			iSpreadProb /= 2;
		}

		iSpreadProb += (((GC.getNumCorporationInfos() - pCity->getCorporationCount()) * (100 - iSpreadProb)) / GC.getNumCorporationInfos());

		if (GC.getGameINLINE().getSorenRandNum(100, "Unit Spread Corporation") < iSpreadProb)
		{
			pCity->setHasCorporation(eCorporation, true, true, false);
		}
		else
		{
			CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_CORPORATION_FAILED_TO_SPREAD", getNameKey(), GC.getCorporationInfo(eCorporation).getChar(), pCity->getNameKey());
			gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_NOSPREAD", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE());
		}
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_SPREAD_CORPORATION);
	}

	kill(true);

	return true;
}


bool CvUnit::canJoin(const CvPlot* pPlot, SpecialistTypes eSpecialist) const
{
	CvCity* pCity;

	if (eSpecialist == NO_SPECIALIST)
	{
		return false;
	}

	if (!(m_pUnitInfo->getGreatPeoples(eSpecialist)))
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (!(pCity->canJoin()))
	{
		return false;
	}

	if (pCity->getTeam() != getTeam())
	{
		return false;
	}

	if (isDelayedDeath())
	{
		return false;
	}

	return true;
}


bool CvUnit::join(SpecialistTypes eSpecialist)
{
	CvCity* pCity;

	if (!canJoin(plot(), eSpecialist))
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		pCity->changeFreeSpecialistCount(eSpecialist, 1);
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_JOIN);
	}

	kill(true);

	return true;
}


bool CvUnit::canConstruct(const CvPlot* pPlot, BuildingTypes eBuilding, bool bTestVisible) const
{
	CvCity* pCity;

	if (eBuilding == NO_BUILDING)
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (getTeam() != pCity->getTeam())
	{
		return false;
	}

	if (pCity->getNumRealBuilding(eBuilding) > 0)
	{
		return false;
	}

	if (!(m_pUnitInfo->getForceBuildings(eBuilding)))
	{
		if (!(m_pUnitInfo->getBuildings(eBuilding)))
		{
			return false;
		}

		if (!(pCity->canConstruct(eBuilding, false, bTestVisible, true)))
		{
			return false;
		}
	}

	if (isDelayedDeath())
	{
		return false;
	}

	return true;
}


bool CvUnit::construct(BuildingTypes eBuilding)
{
	CvCity* pCity;

	if (!canConstruct(plot(), eBuilding))
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		pCity->setNumRealBuilding(eBuilding, pCity->getNumRealBuilding(eBuilding) + 1);

		gDLL->getEventReporterIFace()->buildingBuilt(pCity, eBuilding);
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_CONSTRUCT);
	}

	kill(true);

	return true;
}


TechTypes CvUnit::getDiscoveryTech() const
{
	return ::getDiscoveryTech(getUnitType(), getOwnerINLINE());
}


int CvUnit::getDiscoverResearch(TechTypes eTech) const
{
	int iResearch;

	iResearch = (m_pUnitInfo->getBaseDiscover() + (m_pUnitInfo->getDiscoverMultiplier() * GET_TEAM(getTeam()).getTotalPopulation()));

	iResearch *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getUnitDiscoverPercent();
	iResearch /= 100;

    if (eTech != NO_TECH)
    {
        iResearch = std::min(GET_TEAM(getTeam()).getResearchLeft(eTech), iResearch);
    }

	return std::max(0, iResearch);
}


bool CvUnit::canDiscover(const CvPlot* pPlot) const
{
	TechTypes eTech;

	eTech = getDiscoveryTech();

	if (eTech == NO_TECH)
	{
		return false;
	}

	if (getDiscoverResearch(eTech) == 0)
	{
		return false;
	}

	if (isDelayedDeath())
	{
		return false;
	}

	return true;
}


bool CvUnit::discover()
{
	TechTypes eDiscoveryTech;

	if (!canDiscover(plot()))
	{
		return false;
	}

	eDiscoveryTech = getDiscoveryTech();
	FAssertMsg(eDiscoveryTech != NO_TECH, "DiscoveryTech is not assigned a valid value");

	GET_TEAM(getTeam()).changeResearchProgress(eDiscoveryTech, getDiscoverResearch(eDiscoveryTech), getOwnerINLINE());

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_DISCOVER);
	}

	kill(true);

	return true;
}


int CvUnit::getMaxHurryProduction(CvCity* pCity) const
{
	int iProduction;

	iProduction = (m_pUnitInfo->getBaseHurry() + (m_pUnitInfo->getHurryMultiplier() * pCity->getPopulation()));

	iProduction *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getUnitHurryPercent();
	iProduction /= 100;

	return std::max(0, iProduction);
}


int CvUnit::getHurryProduction(const CvPlot* pPlot) const
{
	CvCity* pCity;
	int iProduction;

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return 0;
	}

	iProduction = getMaxHurryProduction(pCity);

	iProduction = std::min(pCity->productionLeft(), iProduction);

	return std::max(0, iProduction);
}


bool CvUnit::canHurry(const CvPlot* pPlot, bool bTestVisible) const
{
	if (isDelayedDeath())
	{
		return false;
	}

	CvCity* pCity;

	if (getHurryProduction(pPlot) == 0)
	{
		return false;
	}

	pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getProductionTurnsLeft() == 1)
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (!(pCity->isProductionBuilding()))
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::hurry()
{
	CvCity* pCity;

	if (!canHurry(plot()))
	{
		return false;
	}

	pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		pCity->changeProduction(getHurryProduction(plot()));
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_HURRY);
	}

	kill(true);

	return true;
}


int CvUnit::getTradeGold(const CvPlot* pPlot) const
{
	CvCity* pCapitalCity;
	CvCity* pCity;
	int iGold;

	pCity = pPlot->getPlotCity();
	pCapitalCity = GET_PLAYER(getOwnerINLINE()).getCapitalCity();

	if (pCity == NULL)
	{
		return 0;
	}

	iGold = (m_pUnitInfo->getBaseTrade() + (m_pUnitInfo->getTradeMultiplier() * ((pCapitalCity != NULL) ? pCity->calculateTradeProfit(pCapitalCity) : 0)));

	iGold *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getUnitTradePercent();
	iGold /= 100;

	return std::max(0, iGold);
}


bool CvUnit::canTrade(const CvPlot* pPlot, bool bTestVisible) const
{
	if (isDelayedDeath())
	{
		return false;
	}

	CvCity* pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (getTradeGold(pPlot) == 0)
	{
		return false;
	}

	if (!canEnterArea(pPlot->getTeam(), pPlot->area()))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (pCity->getTeam() == getTeam())
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::trade()
{
	if (!canTrade(plot()))
	{
		return false;
	}

	GET_PLAYER(getOwnerINLINE()).changeGold(getTradeGold(plot()));

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_TRADE);
	}

	kill(true);

	return true;
}


int CvUnit::getGreatWorkCulture(const CvPlot* pPlot) const
{
	int iCulture;

	iCulture = m_pUnitInfo->getGreatWorkCulture();

	iCulture *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getUnitGreatWorkPercent();
	iCulture /= 100;

	return std::max(0, iCulture);
}


bool CvUnit::canGreatWork(const CvPlot* pPlot) const
{
	if (isDelayedDeath())
	{
		return false;
	}

	CvCity* pCity = pPlot->getPlotCity();

	if (pCity == NULL)
	{
		return false;
	}

	if (pCity->getOwnerINLINE() != getOwnerINLINE())
	{
		return false;
	}

	if (getGreatWorkCulture(pPlot) == 0)
	{
		return false;
	}

	return true;
}


bool CvUnit::greatWork()
{
	if (!canGreatWork(plot()))
	{
		return false;
	}

	CvCity* pCity = plot()->getPlotCity();

	if (pCity != NULL)
	{
		pCity->setCultureUpdateTimer(0);
		pCity->setOccupationTimer(0);

		int iCultureToAdd = 100 * getGreatWorkCulture(plot());
		int iNumTurnsApplied = (GC.getDefineINT("GREAT_WORKS_CULTURE_TURNS") * GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getUnitGreatWorkPercent()) / 100;

		for (int i = 0; i < iNumTurnsApplied; ++i)
		{
			pCity->changeCultureTimes100(getOwnerINLINE(), iCultureToAdd / iNumTurnsApplied, true, true);
		}

		if (iNumTurnsApplied > 0)
		{
			pCity->changeCultureTimes100(getOwnerINLINE(), iCultureToAdd % iNumTurnsApplied, false, true);
		}
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_GREAT_WORK);
	}

	kill(true);

	return true;
}


int CvUnit::getEspionagePoints(const CvPlot* pPlot) const
{
	int iEspionagePoints;

	iEspionagePoints = m_pUnitInfo->getEspionagePoints();

	iEspionagePoints *= GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getUnitGreatWorkPercent();
	iEspionagePoints /= 100;

	return std::max(0, iEspionagePoints);
}

bool CvUnit::canInfiltrate(const CvPlot* pPlot, bool bTestVisible) const
{
	if (isDelayedDeath())
	{
		return false;
	}

	if (getEspionagePoints(NULL) == 0)
	{
		return false;
	}

	CvCity* pCity = pPlot->getPlotCity();
	if (pCity == NULL || pCity->isBarbarian())
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (NULL != pCity && pCity->getTeam() == getTeam())
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::infiltrate()
{
	if (!canInfiltrate(plot()))
	{
		return false;
	}

	int iPoints = getEspionagePoints(NULL);
	GET_TEAM(getTeam()).changeEspionagePointsAgainstTeam(GET_PLAYER(plot()->getOwnerINLINE()).getTeam(), iPoints);
	GET_TEAM(getTeam()).changeEspionagePointsEver(iPoints);

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_INFILTRATE);
	}

	kill(true);

	return true;
}


bool CvUnit::canEspionage(const CvPlot* pPlot, bool bTestVisible) const
{
	if (isDelayedDeath())
	{
		return false;
	}

	if (!isSpy())
	{
		return false;
	}

	PlayerTypes ePlotOwner = pPlot->getOwnerINLINE();
	if (NO_PLAYER == ePlotOwner)
	{
		return false;
	}

	CvPlayer& kTarget = GET_PLAYER(ePlotOwner);

	if (kTarget.isBarbarian())
	{
		return false;
	}

	if (kTarget.getTeam() == getTeam())
	{
		return false;
	}

	if (GET_TEAM(getTeam()).isVassal(kTarget.getTeam()))
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (isMadeAttack())
		{
			return false;
		}

		if (hasMoved())
		{
			return false;
		}

		if (kTarget.getTeam() != getTeam() && !isInvisible(kTarget.getTeam(), false))
		{
			return false;
		}
	}

	return true;
}

bool CvUnit::espionage(EspionageMissionTypes eMission, int iData)
{
	if (!canEspionage(plot()))
	{
		return false;
	}

	PlayerTypes eTargetPlayer = plot()->getOwnerINLINE();

	if (NO_ESPIONAGEMISSION == eMission)
	{
		FAssert(GET_PLAYER(getOwnerINLINE()).isHuman());
		CvPopupInfo* pInfo = new CvPopupInfo(BUTTONPOPUP_DOESPIONAGE);
		if (NULL != pInfo)
		{
			gDLL->getInterfaceIFace()->addPopup(pInfo, getOwnerINLINE(), true);
		}
	}
	else if (GC.getEspionageMissionInfo(eMission).isTwoPhases() && -1 == iData)
	{
		FAssert(GET_PLAYER(getOwnerINLINE()).isHuman());
		CvPopupInfo* pInfo = new CvPopupInfo(BUTTONPOPUP_DOESPIONAGE_TARGET);
		if (NULL != pInfo)
		{
			pInfo->setData1(eMission);
			gDLL->getInterfaceIFace()->addPopup(pInfo, getOwnerINLINE(), true);
		}
	}
	else
	{
		if (testSpyIntercepted(eTargetPlayer, GC.getEspionageMissionInfo(eMission).getDifficultyMod()))
		{
			return false;
		}

		if (GET_PLAYER(getOwnerINLINE()).doEspionageMission(eMission, eTargetPlayer, plot(), iData, this))
		{
			if (plot()->isActiveVisible(false))
			{
				NotifyEntity(MISSION_ESPIONAGE);
			}

			if (!testSpyIntercepted(eTargetPlayer, GC.getDefineINT("ESPIONAGE_SPY_MISSION_ESCAPE_MOD")))
			{
				setFortifyTurns(0);
				setMadeAttack(true);
				finishMoves();

				CvCity* pCapital = GET_PLAYER(getOwnerINLINE()).getCapitalCity();
				if (NULL != pCapital)
				{
					setXY(pCapital->getX_INLINE(), pCapital->getY_INLINE(), false, false, false);

					CvWString szBuffer = gDLL->getText("TXT_KEY_ESPIONAGE_SPY_SUCCESS", getNameKey(), pCapital->getNameKey());
					gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_POSITIVE_DINK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), pCapital->getX_INLINE(), pCapital->getY_INLINE(), true, true);
				}
			}

			return true;
		}
	}

	return false;
}

bool CvUnit::testSpyIntercepted(PlayerTypes eTargetPlayer, int iModifier)
{
	CvPlayer& kTargetPlayer = GET_PLAYER(eTargetPlayer);

	if (kTargetPlayer.isBarbarian())
	{
		return false;
	}

	if (GC.getGameINLINE().getSorenRandNum(10000, "Spy Interception") >= getSpyInterceptPercent(kTargetPlayer.getTeam()) * (100 + iModifier))
	{
		return false;
	}

	CvString szFormatNoReveal;
	CvString szFormatReveal;

	if (GET_TEAM(kTargetPlayer.getTeam()).getCounterespionageModAgainstTeam(getTeam()) > 0)
	{
		szFormatNoReveal = "TXT_KEY_SPY_INTERCEPTED_MISSION";
		szFormatReveal = "TXT_KEY_SPY_INTERCEPTED_MISSION_REVEAL";
	}
	else if (plot()->isEspionageCounterSpy(kTargetPlayer.getTeam()))
	{
		szFormatNoReveal = "TXT_KEY_SPY_INTERCEPTED_SPY";
		szFormatReveal = "TXT_KEY_SPY_INTERCEPTED_SPY_REVEAL";
	}
	else
	{
		szFormatNoReveal = "TXT_KEY_SPY_INTERCEPTED";
		szFormatReveal = "TXT_KEY_SPY_INTERCEPTED_REVEAL";
	}

	CvWString szCityName = kTargetPlayer.getCivilizationShortDescription();
	CvCity* pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), eTargetPlayer, kTargetPlayer.getTeam(), true, false);
	if (pClosestCity != NULL)
	{
		szCityName = pClosestCity->getName();
	}

	CvWString szBuffer = gDLL->getText(szFormatReveal.GetCString(), GET_PLAYER(getOwnerINLINE()).getCivilizationAdjectiveKey(), getNameKey(), kTargetPlayer.getCivilizationAdjectiveKey(), szCityName.GetCString());
	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);

	if (GC.getGameINLINE().getSorenRandNum(100, "Spy Reveal identity") < GC.getDefineINT("ESPIONAGE_SPY_REVEAL_IDENTITY_PERCENT"))
	{
		if (!isEnemy(kTargetPlayer.getTeam()))
		{
			GET_PLAYER(eTargetPlayer).AI_changeMemoryCount(getOwnerINLINE(), MEMORY_SPY_CAUGHT, 1);
		}

		gDLL->getInterfaceIFace()->addMessage(eTargetPlayer, true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
	}
	else
	{
		szBuffer = gDLL->getText(szFormatNoReveal.GetCString(), getNameKey(), kTargetPlayer.getCivilizationAdjectiveKey(), szCityName.GetCString());
		gDLL->getInterfaceIFace()->addMessage(eTargetPlayer, true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_EXPOSE", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
	}

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_SURRENDER);
	}

	kill(true);

	return true;
}

int CvUnit::getSpyInterceptPercent(TeamTypes eTargetTeam) const
{
	FAssert(isSpy());
	FAssert(getTeam() != eTargetTeam);

	int iSuccess = 0;

	int iTargetPoints = GET_TEAM(eTargetTeam).getEspionagePointsEver();
	int iOurPoints = GET_TEAM(getTeam()).getEspionagePointsEver();
	iSuccess += (GC.getDefineINT("ESPIONAGE_INTERCEPT_SPENDING_MAX") * iTargetPoints) / std::max(1, iTargetPoints + iOurPoints);

	if (plot()->isEspionageCounterSpy(eTargetTeam))
	{
		iSuccess += GC.getDefineINT("ESPIONAGE_INTERCEPT_COUNTERSPY");
	}

	if (GET_TEAM(eTargetTeam).getCounterespionageModAgainstTeam(getTeam()) > 0)
	{
		iSuccess += GC.getDefineINT("ESPIONAGE_INTERCEPT_COUNTERESPIONAGE_MISSION");
	}

	if (0 == getFortifyTurns() || plot()->plotCount(PUF_isSpy, -1, -1, NO_PLAYER, getTeam()) > 0)
	{
		iSuccess += GC.getDefineINT("ESPIONAGE_INTERCEPT_RECENT_MISSION");
	}

	return std::min(100, std::max(0, iSuccess));
}

bool CvUnit::isIntruding() const
{
	TeamTypes eLocalTeam = plot()->getTeam();

	if (NO_TEAM == eLocalTeam || eLocalTeam == getTeam())
	{
		return false;
	}

	if (GET_TEAM(eLocalTeam).isVassal(getTeam()))
	{
		return false;
	}

	return true;
}

bool CvUnit::canGoldenAge(const CvPlot* pPlot, bool bTestVisible) const
{
	if (!isGoldenAge())
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (GET_PLAYER(getOwnerINLINE()).unitsRequiredForGoldenAge() > GET_PLAYER(getOwnerINLINE()).unitsGoldenAgeReady())
		{
			return false;
		}
	}

	return true;
}


bool CvUnit::goldenAge()
{
	if (!canGoldenAge(plot()))
	{
		return false;
	}

	GET_PLAYER(getOwnerINLINE()).killGoldenAgeUnits(this);

	GET_PLAYER(getOwnerINLINE()).changeGoldenAgeTurns(GET_PLAYER(getOwnerINLINE()).getGoldenAgeLength());
	GET_PLAYER(getOwnerINLINE()).changeNumUnitGoldenAges(1);

	if (plot()->isActiveVisible(false))
	{
		NotifyEntity(MISSION_GOLDEN_AGE);
	}

	kill(true);

	return true;
}


bool CvUnit::canBuild(const CvPlot* pPlot, BuildTypes eBuild, bool bTestVisible) const
{
    FAssertMsg(eBuild < GC.getNumBuildInfos(), "Index out of bounds");

//FfH: Modified by Kael 08/31/2007 (so AI workers can upgrade mana nodes)
//	if (!(m_pUnitInfo->getBuilds(eBuild)))
//	{
//		return false;
//	}
//
//	if (!(GET_PLAYER(getOwnerINLINE()).canBuild(pPlot, eBuild, false, bTestVisible)))
//	{
//		return false;
//	}
//
//	if (!pPlot->isValidDomainForAction(*this))
//	{
//		return false;
//	}
	if (!(GET_PLAYER(getOwnerINLINE()).canBuild(pPlot, eBuild, false, bTestVisible)))
	{
		return false;
	}
	if (!pPlot->isValidDomainForAction(*this))
	{
		return false;
	}
    if (!(GET_PLAYER(getOwnerINLINE()).isHuman()))
    {
        if (GC.getDefineINT("BONUS_MANA") != -1)
        {
            if (pPlot->getBonusType(getTeam()) == GC.getDefineINT("BONUS_MANA"))
            {
                if (getUnitClassType() == GC.getInfoTypeForString("UNITCLASS_WORKER"))
                {
                    return true;
                }
            }
        }
    }
	if (!(m_pUnitInfo->getBuilds(eBuild)))
	{
		return false;
	}
//FfH: End Modify

	return true;
}

// Returns true if build finished...
bool CvUnit::build(BuildTypes eBuild)
{
	bool bFinished;

	FAssertMsg(eBuild < GC.getNumBuildInfos(), "Invalid Build");

	if (!canBuild(plot(), eBuild))
	{
		return false;
	}

	// Note: notify entity must come before changeBuildProgress - because once the unit is done building,
	// that function will notify the entity to stop building.
	NotifyEntity((MissionTypes)GC.getBuildInfo(eBuild).getMissionType());

	bFinished = plot()->changeBuildProgress(eBuild, workRate(false), getTeam());

	GET_PLAYER(getOwnerINLINE()).changeGold(-(GET_PLAYER(getOwnerINLINE()).getBuildCost(plot(), eBuild)));

	finishMoves(); // needs to be at bottom because movesLeft() can affect workRate()...

	if (bFinished)
	{
        // < JImprovementCultureBorders Mod Start >
        if (GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).isOutsideBorders())
        {
            int iCultureBorderRange = GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).getCultureBorderRange();
            if (iCultureBorderRange > -1)
            {
                if (plot()->getCultureBorderRange() != iCultureBorderRange)
                {
                    plot()->setCultureBorderRange(iCultureBorderRange);
                }
                if (plot()->getImprovementOwner() != getOwner())
                {
                    plot()->setImprovementOwner(getOwner());
                }
                int iTileCultureChange;
                iTileCultureChange = GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).getSameTileCultureChange();
                if (plot()->getSameTileCultureChange() != iTileCultureChange)
                {
                    plot()->setSameTileCultureChange(iTileCultureChange);
                }
                iTileCultureChange = GC.getImprovementInfo((ImprovementTypes) GC.getBuildInfo(eBuild).getImprovement()).getAdjacentTileCultureChange();
                if (plot()->getAdjacentTileCultureChange() != iTileCultureChange)
                {
                    plot()->setAdjacentTileCultureChange(iTileCultureChange);
                }
                //plot()->changeCultureBorderCount(1);
                /*if (iCultureBorderRange > 0)
                {
                    int iX = plot()->getX_INLINE();
                    int iY = plot()->getY_INLINE();
                    int iStartX = iX - iCultureBorderRange;
                    int iStopX = iX + iCultureBorderRange + 1;
                    int iStartY = iY - iCultureBorderRange;
                    int iStopY = iY + iCultureBorderRange + 1;
                    for (int iIX = iStartX; iIX < iStopX; iIX++)
                    {
                        for (int iIY = iStartY; iIY < iStopY; iIY++)
                        {
                            CvPlot* pLoopPlot = GC.getMap().plot(iIX, iIY);

                            if (pLoopPlot != NULL)
                            {
                                if (!(iIX == iX && iIY == iY))
                                {
                                    pLoopPlot->changeCultureBorderCount(1);
                                }
                            }
                        }
                    }
                }*/
            }
        }
        // < JImprovementCultureBorders Mod End >
		if (GC.getBuildInfo(eBuild).isKill())
		{
			kill(true);
		}
	}

	// Python Event
	gDLL->getEventReporterIFace()->unitBuildImprovement(this, eBuild, bFinished);

	return bFinished;
}


bool CvUnit::canPromote(PromotionTypes ePromotion, int iLeaderUnitId) const
{
	if (iLeaderUnitId >= 0)
	{
		if (iLeaderUnitId == getID())
		{
			return false;
		}

		// The command is always possible if it's coming from a Warlord unit that gives just experience points
		CvUnit* pWarlord = GET_PLAYER(getOwnerINLINE()).getUnit(iLeaderUnitId);
		if (pWarlord &&
			NO_UNIT != pWarlord->getUnitType() &&
			pWarlord->getUnitInfo().getLeaderExperience() > 0 &&
			NO_PROMOTION == pWarlord->getUnitInfo().getLeaderPromotion() &&
			canAcquirePromotionAny())
		{
			return true;
		}
	}

	if (ePromotion == NO_PROMOTION)
	{
		return false;
	}

	if (!canAcquirePromotion(ePromotion))
	{
		return false;
	}

//FfH Units: Added by Kael 08/04/2007
    if (getFreePromotionPick() > 0)
    {
        return true;
    }
//FfH: End Add

	if (GC.getPromotionInfo(ePromotion).isLeader())
	{
		if (iLeaderUnitId >= 0)
		{
			CvUnit* pWarlord = GET_PLAYER(getOwnerINLINE()).getUnit(iLeaderUnitId);
			if (pWarlord && NO_UNIT != pWarlord->getUnitType())
			{
				return (pWarlord->getUnitInfo().getLeaderPromotion() == ePromotion);
			}
		}
		return false;
	}
	else
	{
		if (!isPromotionReady())
		{
			return false;
		}
	}

	return true;
}

void CvUnit::promote(PromotionTypes ePromotion, int iLeaderUnitId)
{
	if (!canPromote(ePromotion, iLeaderUnitId))
	{
		return;
	}

	if (iLeaderUnitId >= 0)
	{
		CvUnit* pWarlord = GET_PLAYER(getOwnerINLINE()).getUnit(iLeaderUnitId);
		if (pWarlord)
		{
			pWarlord->giveExperience();
			if (!pWarlord->getNameNoDesc().empty())
			{
				setName(pWarlord->getNameKey());
			}

			//update graphics models
			m_eLeaderUnitType = pWarlord->getUnitType();
			reloadEntity();
		}
	}

//FfH Units: Modified by Kael 08/04/2007
//	if (!GC.getPromotionInfo(ePromotion).isLeader())
	if ((!GC.getPromotionInfo(ePromotion).isLeader()) && getFreePromotionPick() == 0)
//FfH: End Modify

	{
		changeLevel(1);
		changeDamage(-(getDamage() / 2));
	}

//FfH: Added by Kael 01/09/2008
    if (getFreePromotionPick() > 0)
    {
        changeFreePromotionPick(-1);
    }
//FfH: End Add

	setHasPromotion(ePromotion, true);

	testPromotionReady();

	if (IsSelected())
	{
		gDLL->getInterfaceIFace()->playGeneralSound(GC.getPromotionInfo(ePromotion).getSound());

		gDLL->getInterfaceIFace()->setDirty(UnitInfo_DIRTY_BIT, true);
	}
	else
	{
		setInfoBarDirty(true);
	}

	gDLL->getEventReporterIFace()->unitPromoted(this, ePromotion);
}

bool CvUnit::lead(int iUnitId)
{
	if (!canLead(plot(), iUnitId))
	{
		return false;
	}

	PromotionTypes eLeaderPromotion = (PromotionTypes)m_pUnitInfo->getLeaderPromotion();

	if (-1 == iUnitId)
	{
		CvPopupInfo* pInfo = new CvPopupInfo(BUTTONPOPUP_LEADUNIT, eLeaderPromotion, getID());
		if (pInfo)
		{
			gDLL->getInterfaceIFace()->addPopup(pInfo, getOwnerINLINE(), true);
		}
		return false;
	}
	else
	{
		CvUnit* pUnit = GET_PLAYER(getOwnerINLINE()).getUnit(iUnitId);

		if (!pUnit || !pUnit->canPromote(eLeaderPromotion, getID()))
		{
			return false;
		}

		pUnit->promote(eLeaderPromotion, getID());

		if (plot()->isActiveVisible(false))
		{
			NotifyEntity(MISSION_LEAD);
		}

		kill(true);

		return true;
	}
}


int CvUnit::canLead(const CvPlot* pPlot, int iUnitId) const
{
	PROFILE_FUNC();

	if (isDelayedDeath())
	{
		return 0;
	}

	if (NO_UNIT == getUnitType())
	{
		return 0;
	}

	int iNumUnits = 0;
	CvUnitInfo& kUnitInfo = getUnitInfo();

	if (-1 == iUnitId)
	{
		CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
		while(pUnitNode != NULL)
		{
			CvUnit* pUnit = ::getUnit(pUnitNode->m_data);
			pUnitNode = pPlot->nextUnitNode(pUnitNode);

			if (pUnit && pUnit != this && pUnit->getOwnerINLINE() == getOwnerINLINE() && pUnit->canPromote((PromotionTypes)kUnitInfo.getLeaderPromotion(), getID()))
			{
				++iNumUnits;
			}
		}
	}
	else
	{
		CvUnit* pUnit = GET_PLAYER(getOwnerINLINE()).getUnit(iUnitId);
		if (pUnit && pUnit != this && pUnit->canPromote((PromotionTypes)kUnitInfo.getLeaderPromotion(), getID()))
		{
			iNumUnits = 1;
		}
	}
	return iNumUnits;
}


int CvUnit::canGiveExperience(const CvPlot* pPlot) const
{
	int iNumUnits = 0;

	if (NO_UNIT != getUnitType() && m_pUnitInfo->getLeaderExperience() > 0)
	{
		CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
		while(pUnitNode != NULL)
		{
			CvUnit* pUnit = ::getUnit(pUnitNode->m_data);
			pUnitNode = pPlot->nextUnitNode(pUnitNode);

			if (pUnit && pUnit != this && pUnit->getOwnerINLINE() == getOwnerINLINE() && pUnit->canAcquirePromotionAny())
			{
				++iNumUnits;
			}
		}
	}

	return iNumUnits;
}

bool CvUnit::giveExperience()
{
	CvPlot* pPlot = plot();

	if (pPlot)
	{
		int iNumUnits = canGiveExperience(pPlot);
		if (iNumUnits > 0)
		{
			int iTotalExperience = getStackExperienceToGive(iNumUnits);

			int iMinExperiencePerUnit = iTotalExperience / iNumUnits;
			int iRemainder = iTotalExperience % iNumUnits;

			CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();
			int i = 0;
			while(pUnitNode != NULL)
			{
				CvUnit* pUnit = ::getUnit(pUnitNode->m_data);
				pUnitNode = pPlot->nextUnitNode(pUnitNode);

				if (pUnit && pUnit != this && pUnit->getOwnerINLINE() == getOwnerINLINE() && pUnit->canAcquirePromotionAny())
				{
					pUnit->changeExperience(i < iRemainder ? iMinExperiencePerUnit+1 : iMinExperiencePerUnit);
					pUnit->testPromotionReady();
				}

				i++;
			}

			return true;
		}
	}

	return false;
}

int CvUnit::getStackExperienceToGive(int iNumUnits) const
{
	return (m_pUnitInfo->getLeaderExperience() * (100 + std::min(50, (iNumUnits - 1) * GC.getDefineINT("WARLORD_EXTRA_EXPERIENCE_PER_UNIT_PERCENT")))) / 100;
}

int CvUnit::upgradePrice(UnitTypes eUnit) const
{
	int iPrice;

	CyArgsList argsList;
	argsList.add(getOwner());
	argsList.add(getID());
	argsList.add((int) eUnit);
	long lResult=0;
	gDLL->getPythonIFace()->callFunction(PYGameModule, "getUpgradePriceOverride", argsList.makeFunctionArgs(), &lResult);
	if (lResult >= 0)
	{
		return lResult;
	}

	if (isBarbarian())
	{
		return 0;
	}

	iPrice = GC.getDefineINT("BASE_UNIT_UPGRADE_COST");

	iPrice += (std::max(0, (GET_PLAYER(getOwnerINLINE()).getProductionNeeded(eUnit) - GET_PLAYER(getOwnerINLINE()).getProductionNeeded(getUnitType()))) * GC.getDefineINT("UNIT_UPGRADE_COST_PER_PRODUCTION"));

	if (!isHuman() && !isBarbarian())
	{
		iPrice *= GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIUnitUpgradePercent();
		iPrice /= 100;

		iPrice *= std::max(0, ((GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIPerEraModifier() * GET_PLAYER(getOwnerINLINE()).getCurrentEra()) + 100));
		iPrice /= 100;
	}

	iPrice -= (iPrice * getUpgradeDiscount()) / 100;

//FfH Traits: Added by Kael 08/02/2007
    iPrice += (iPrice * GET_PLAYER(getOwnerINLINE()).getUpgradeCostModifier()) / 100;
	CvCity* pCity = getUpgradeCity(eUnit, true);
	if (pCity != NULL)
    {
        iPrice += (iPrice * pCity->getUpgradeCostModifier()) / 100;
    }
//FfH: End Add

	return iPrice;
}


bool CvUnit::upgradeAvailable(UnitTypes eFromUnit, UnitClassTypes eToUnitClass, int iCount) const
{
	UnitTypes eLoopUnit;
	int iI;
	int numUnitClassInfos = GC.getNumUnitClassInfos();

	if (iCount > numUnitClassInfos)
	{
		return false;
	}

	CvUnitInfo &fromUnitInfo = GC.getUnitInfo(eFromUnit);

	if (fromUnitInfo.getUpgradeUnitClass(eToUnitClass))
	{
		return true;
	}

	for (iI = 0; iI < numUnitClassInfos; iI++)
	{
		if (fromUnitInfo.getUpgradeUnitClass(iI))
		{
			eLoopUnit = ((UnitTypes)(GC.getCivilizationInfo(getCivilizationType()).getCivilizationUnits(iI)));
			if (eLoopUnit != NO_UNIT)
			{
				if (upgradeAvailable(eLoopUnit, eToUnitClass, (iCount + 1)))
				{
					return true;
				}
			}
		}
	}

	return false;
}


bool CvUnit::canUpgrade(UnitTypes eUnit, bool bTestVisible) const
{
	if (eUnit == NO_UNIT)
	{
		return false;
	}

	if(!isReadyForUpgrade())
	{
		return false;
	}

	if (!bTestVisible)
	{
		if (GET_PLAYER(getOwnerINLINE()).getGold() < upgradePrice(eUnit))
		{
			return false;
		}
	}

//FfH Units: Added by Kael 05/24/2008
    if (getLevel() < GC.getUnitInfo(eUnit).getMinLevel())
	{
		return false;
	}

    if (GC.getUnitInfo(eUnit).isDisableUpgradeTo())
    {
        return false;
    }

	if (GET_PLAYER(getOwnerINLINE()).isUnitClassMaxedOut((UnitClassTypes)(GC.getUnitInfo(eUnit).getUnitClassType())))
	{
		return false;
	}
//FfH: End Add

	if (hasUpgrade(eUnit))
	{
		return true;
	}

	return false;
}

bool CvUnit::isReadyForUpgrade() const
{
	if (!canMove())
	{
		return false;
	}

	if (plot()->getTeam() != getTeam())
	{
		return false;
	}

	return true;
}

// has upgrade is used to determine if an upgrade is possible,
// it specifically does not check whether the unit can move, whether the current plot is owned, enough gold
// those are checked in canUpgrade()
// does not search all cities, only checks the closest one
bool CvUnit::hasUpgrade(bool bSearch) const
{
	return (getUpgradeCity(bSearch) != NULL);
}

// has upgrade is used to determine if an upgrade is possible,
// it specifically does not check whether the unit can move, whether the current plot is owned, enough gold
// those are checked in canUpgrade()
// does not search all cities, only checks the closest one
bool CvUnit::hasUpgrade(UnitTypes eUnit, bool bSearch) const
{
	return (getUpgradeCity(eUnit, bSearch) != NULL);
}

// finds the 'best' city which has a valid upgrade for the unit,
// it specifically does not check whether the unit can move, or if the player has enough gold to upgrade
// those are checked in canUpgrade()
// if bSearch is true, it will check every city, if not, it will only check the closest valid city
// NULL result means the upgrade is not possible
CvCity* CvUnit::getUpgradeCity(bool bSearch) const
{
	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	UnitAITypes eUnitAI = AI_getUnitAIType();
	CvArea* pArea = area();

	int iCurrentValue = kPlayer.AI_unitValue(getUnitType(), eUnitAI, pArea);

	int iBestSearchValue = MAX_INT;
	CvCity* pBestUpgradeCity = NULL;

	for (int iI = 0; iI < GC.getNumUnitInfos(); iI++)
	{
		int iNewValue = kPlayer.AI_unitValue(((UnitTypes)iI), eUnitAI, pArea);
		if (iNewValue > iCurrentValue)
		{
			int iSearchValue;
			CvCity* pUpgradeCity = getUpgradeCity((UnitTypes)iI, bSearch, &iSearchValue);
			if (pUpgradeCity != NULL)
			{
				// if not searching or close enough, then this match will do
				if (!bSearch || iSearchValue < 16)
				{
					return pUpgradeCity;
				}

				if (iSearchValue < iBestSearchValue)
				{
					iBestSearchValue = iSearchValue;
					pBestUpgradeCity = pUpgradeCity;
				}
			}
		}
	}

	return pBestUpgradeCity;
}

// finds the 'best' city which has a valid upgrade for the unit, to eUnit type
// it specifically does not check whether the unit can move, or if the player has enough gold to upgrade
// those are checked in canUpgrade()
// if bSearch is true, it will check every city, if not, it will only check the closest valid city
// if iSearchValue non NULL, then on return it will be the city's proximity value, lower is better
// NULL result means the upgrade is not possible
CvCity* CvUnit::getUpgradeCity(UnitTypes eUnit, bool bSearch, int* iSearchValue) const
{
	if (eUnit == NO_UNIT)
	{
		return false;
	}

	CvPlayerAI& kPlayer = GET_PLAYER(getOwnerINLINE());
	CvUnitInfo& kUnitInfo = GC.getUnitInfo(eUnit);

//FfH: Modified by Kael 05/09/2008
//	if (GC.getCivilizationInfo(kPlayer.getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
//	{
//		return false;
//	}
    if (m_pUnitInfo->getUpgradeCiv() == NO_CIVILIZATION)
    {
        if (GC.getCivilizationInfo(kPlayer.getCivilizationType()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
        {
            return false;
        }
    }
    else
    {
        if (GC.getCivilizationInfo((CivilizationTypes)m_pUnitInfo->getUpgradeCiv()).getCivilizationUnits(kUnitInfo.getUnitClassType()) != eUnit)
        {
            return false;
        }
    }
//FfH: End Modify

	if (!upgradeAvailable(getUnitType(), ((UnitClassTypes)(kUnitInfo.getUnitClassType()))))
	{
		return false;
	}

	if (kUnitInfo.getCargoSpace() < getCargo())
	{
		return false;
	}

	CLLNode<IDInfo>* pUnitNode = plot()->headUnitNode();
	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = plot()->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (kUnitInfo.getSpecialCargo() != NO_SPECIALUNIT)
			{
				if (kUnitInfo.getSpecialCargo() != pLoopUnit->getSpecialUnitType())
				{
					return false;
				}
			}

			if (kUnitInfo.getDomainCargo() != NO_DOMAIN)
			{
				if (kUnitInfo.getDomainCargo() != pLoopUnit->getDomainType())
				{
					return false;
				}
			}
		}
	}

	// sea units must be built on the coast
	bool bCoastalOnly = (getDomainType() == DOMAIN_SEA);

	// results
	int iBestValue = MAX_INT;
	CvCity* pBestCity = NULL;

	// if search is true, check every city for our team
	if (bSearch)
	{
		// air units can travel any distance
		bool bIgnoreDistance = (getDomainType() == DOMAIN_AIR);

		TeamTypes eTeam = getTeam();
		int iArea = getArea();
		int iX = getX_INLINE(), iY = getY_INLINE();

		// check every player on our team's cities
		for (int iI = 0; iI < MAX_PLAYERS; iI++)
		{
			// is this player on our team?
			CvPlayerAI& kLoopPlayer = GET_PLAYER((PlayerTypes)iI);
			if (kLoopPlayer.isAlive() && kLoopPlayer.getTeam() == eTeam)
			{
				int iLoop;
				for (CvCity* pLoopCity = kLoopPlayer.firstCity(&iLoop); pLoopCity != NULL; pLoopCity = kLoopPlayer.nextCity(&iLoop))
				{
					// if coastal only, then make sure we are coast
					CvArea* pWaterArea = NULL;
					if (!bCoastalOnly || ((pWaterArea = pLoopCity->waterArea()) != NULL && !pWaterArea->isLake()))
					{
						// can this city tran this unit?

//FfH Units: Modified by Kael 05/24/2008
//						if (pLoopCity->canTrain(eUnit, false, false, true))
						if (pLoopCity->canUpgrade(eUnit, false, false, true))
//FfH: End Modify

						{
							// if we do not care about distance, then the first match will do
							if (bIgnoreDistance)
							{
								// if we do not care about distance, then return 1 for value
								if (iSearchValue != NULL)
								{
									*iSearchValue = 1;
								}

								return pLoopCity;
							}

							int iValue = plotDistance(iX, iY, pLoopCity->getX_INLINE(), pLoopCity->getY_INLINE());

							// if not same area, not as good (lower numbers are better)
							if (iArea != pLoopCity->getArea() && (!bCoastalOnly || iArea != pWaterArea->getID()))
							{
								iValue *= 16;
							}

							// if we cannot path there, not as good (lower numbers are better)
							if (!generatePath(pLoopCity->plot(), 0, true))
							{
								iValue *= 16;
							}

							if (iValue < iBestValue)
							{
								iBestValue = iValue;
								pBestCity = pLoopCity;
							}
						}
					}
				}
			}
		}
	}
	else
	{
		// find the closest city
		CvCity* pClosestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), NO_PLAYER, getTeam(), true, bCoastalOnly);
		if (pClosestCity != NULL)
		{
			// if we can train, then return this city (otherwise it will return NULL)

//FfH Units: Modified by Kael 08/07/2007
//			if (pClosestCity->canTrain(eUnit, false, false, true))
			if (pClosestCity->canUpgrade(eUnit, false, false, true))
//FfH: End Add

			{
				// did not search, always return 1 for search value
				iBestValue = 1;

				pBestCity = pClosestCity;
			}
		}
	}

	// return the best value, if non-NULL
	if (iSearchValue != NULL)
	{
		*iSearchValue = iBestValue;
	}

	return pBestCity;
}

void CvUnit::upgrade(UnitTypes eUnit)
{
	CvUnit* pUpgradeUnit;

	if (!canUpgrade(eUnit))
	{
		return;
	}

	GET_PLAYER(getOwnerINLINE()).changeGold(-(upgradePrice(eUnit)));

	pUpgradeUnit = GET_PLAYER(getOwnerINLINE()).initUnit(eUnit, getX_INLINE(), getY_INLINE(), AI_getUnitAIType());

	FAssertMsg(pUpgradeUnit != NULL, "UpgradeUnit is not assigned a valid value");

	pUpgradeUnit->joinGroup(getGroup());

	pUpgradeUnit->convert(this);

	pUpgradeUnit->finishMoves();

	if (pUpgradeUnit->getLeaderUnitType() == NO_UNIT)
	{
		if (pUpgradeUnit->getExperience() > GC.getDefineINT("MAX_EXPERIENCE_AFTER_UPGRADE"))
		{
			pUpgradeUnit->setExperience(GC.getDefineINT("MAX_EXPERIENCE_AFTER_UPGRADE"));
		}
	}
}


HandicapTypes CvUnit::getHandicapType() const
{
	return GET_PLAYER(getOwnerINLINE()).getHandicapType();
}


CivilizationTypes CvUnit::getCivilizationType() const
{
	return GET_PLAYER(getOwnerINLINE()).getCivilizationType();
}

const wchar* CvUnit::getVisualCivAdjective(TeamTypes eForTeam) const
{
	if (getVisualOwner(eForTeam) == getOwnerINLINE())
	{
		return GC.getCivilizationInfo(GET_PLAYER(getOwnerINLINE()).getCivilizationType()).getAdjectiveKey();
	}

	return L"";
}

SpecialUnitTypes CvUnit::getSpecialUnitType() const
{
	return ((SpecialUnitTypes)(m_pUnitInfo->getSpecialUnitType()));
}


UnitTypes CvUnit::getCaptureUnitType(CivilizationTypes eCivilization) const
{
	FAssert(eCivilization != NO_CIVILIZATION);
	return ((m_pUnitInfo->getUnitCaptureClassType() == NO_UNITCLASS) ? NO_UNIT : (UnitTypes)GC.getCivilizationInfo(eCivilization).getCivilizationUnits(m_pUnitInfo->getUnitCaptureClassType()));
}


UnitCombatTypes CvUnit::getUnitCombatType() const
{
	return ((UnitCombatTypes)(m_pUnitInfo->getUnitCombatType()));
}


DomainTypes CvUnit::getDomainType() const
{
	return ((DomainTypes)(m_pUnitInfo->getDomainType()));
}


InvisibleTypes CvUnit::getInvisibleType() const
{

//FfH: Modified by Kael 12/03/2007
//	return ((InvisibleTypes)(m_pUnitInfo->getInvisibleType()));
	return ((InvisibleTypes)m_iInvisibleType);
//FfH: End Modify

}

int CvUnit::getNumSeeInvisibleTypes() const
{
	return m_pUnitInfo->getNumSeeInvisibleTypes();
}

InvisibleTypes CvUnit::getSeeInvisibleType(int i) const
{
	return (InvisibleTypes)(m_pUnitInfo->getSeeInvisibleType(i));
}


int CvUnit::flavorValue(FlavorTypes eFlavor) const
{
	return m_pUnitInfo->getFlavorValue(eFlavor);
}


bool CvUnit::isBarbarian() const
{
	return GET_PLAYER(getOwnerINLINE()).isBarbarian();
}


bool CvUnit::isHuman() const
{
	return GET_PLAYER(getOwnerINLINE()).isHuman();
}


int CvUnit::visibilityRange() const
{

//FfH: Modified by Kael 08/10/2007
//	return (GC.getDefineINT("UNIT_VISIBILITY_RANGE") + getExtraVisibilityRange());
    int iRange = GC.getDefineINT("UNIT_VISIBILITY_RANGE");
    iRange += getExtraVisibilityRange();
    if (plot()->getImprovementType() != NO_IMPROVEMENT)
    {
        iRange += GC.getImprovementInfo((ImprovementTypes)plot()->getImprovementType()).getVisibilityChange();
    }
	return iRange;
//FfH: End Modify

}


int CvUnit::baseMoves() const
{
	return (m_pUnitInfo->getMoves() + getExtraMoves() + GET_TEAM(getTeam()).getExtraMoves(getDomainType()));
}


int CvUnit::maxMoves() const
{
	return (baseMoves() * GC.getMOVE_DENOMINATOR());
}


int CvUnit::movesLeft() const
{
	return std::max(0, (maxMoves() - getMoves()));
}


bool CvUnit::canMove() const
{
	if (isDead())
	{
		return false;
	}

	if (getMoves() >= maxMoves())
	{
		return false;
	}

	if (getImmobileTimer() > 0)
	{
		return false;
	}

	return true;
}


bool CvUnit::hasMoved()	const
{
	return (getMoves() > 0);
}


int CvUnit::airRange() const
{
	return (m_pUnitInfo->getAirRange() + getExtraAirRange());
}


int CvUnit::nukeRange() const
{
	return m_pUnitInfo->getNukeRange();
}


// XXX should this test for coal?
bool CvUnit::canBuildRoute() const
{
	int iI;

	for (iI = 0; iI < GC.getNumBuildInfos(); iI++)
	{
		if (GC.getBuildInfo((BuildTypes)iI).getRoute() != NO_ROUTE)
		{
			if (m_pUnitInfo->getBuilds(iI))
			{
				if (GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getBuildInfo((BuildTypes)iI).getTechPrereq())))
				{
					return true;
				}
			}
		}
	}

	return false;
}

BuildTypes CvUnit::getBuildType() const
{
	BuildTypes eBuild;

	if (getGroup()->headMissionQueueNode() != NULL)
	{
		switch (getGroup()->headMissionQueueNode()->m_data.eMissionType)
		{
		case MISSION_MOVE_TO:
			break;

		case MISSION_ROUTE_TO:
			if (getGroup()->getBestBuildRoute(plot(), &eBuild) != NO_ROUTE)
			{
				return eBuild;
			}
			break;

		case MISSION_MOVE_TO_UNIT:
		case MISSION_SKIP:
		case MISSION_SLEEP:
		case MISSION_FORTIFY:
		case MISSION_PLUNDER:
		case MISSION_AIRPATROL:
		case MISSION_SEAPATROL:
		case MISSION_HEAL:
		case MISSION_SENTRY:
		case MISSION_AIRLIFT:
		case MISSION_NUKE:
		case MISSION_RECON:
		case MISSION_PARADROP:
		case MISSION_AIRBOMB:
		case MISSION_BOMBARD:
		case MISSION_RANGE_ATTACK:
		case MISSION_PILLAGE:
		case MISSION_SABOTAGE:
		case MISSION_DESTROY:
		case MISSION_STEAL_PLANS:
		case MISSION_FOUND:
		case MISSION_SPREAD:
		case MISSION_SPREAD_CORPORATION:
		case MISSION_JOIN:
		case MISSION_CONSTRUCT:
		case MISSION_DISCOVER:
		case MISSION_HURRY:
		case MISSION_TRADE:
		case MISSION_GREAT_WORK:
		case MISSION_INFILTRATE:
		case MISSION_GOLDEN_AGE:
		case MISSION_LEAD:
		case MISSION_ESPIONAGE:
		case MISSION_DIE_ANIMATION:
			break;

		case MISSION_BUILD:
			return (BuildTypes)getGroup()->headMissionQueueNode()->m_data.iData1;
			break;

		default:
			FAssert(false);
			break;
		}
	}

	return NO_BUILD;
}


int CvUnit::workRate(bool bMax) const
{
	int iRate;

	if (!bMax)
	{
		if (!canMove())
		{
			return 0;
		}
	}

/*************************************************************************************************/
/**	WorkerRate (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**							Adds the new Workrate Value to the original one						**/
/*************************************************************************************************/
/**								---- Start Original Code ----
    iRate = m_pUnitInfo->getWorkRate();
								----  End Original Code  ----									**/
	iRate = std::max (0, m_pUnitInfo->getWorkRate() + getWorkRateChange());
/*************************************************************************************************/
/**	WorkerRate (PromotionInfos)					END												**/
/*************************************************************************************************/

	iRate *= std::max(0, (GET_PLAYER(getOwnerINLINE()).getWorkerSpeedModifier() + 100));
	iRate /= 100;

	if (!isHuman() && !isBarbarian())
	{
		iRate *= std::max(0, (GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIWorkRateModifier() + 100));
		iRate /= 100;
	}

	return iRate;
}


bool CvUnit::isAnimal() const
{
	return m_pUnitInfo->isAnimal();
}


bool CvUnit::isNoBadGoodies() const
{
	return m_pUnitInfo->isNoBadGoodies();
}


bool CvUnit::isOnlyDefensive() const
{

//FfH Promotions: Added by Kael 08/14/2007
    if (m_bOnlyDefensive)
    {
        return true;
    }
//FfH: End Add
/*************************************************************************************************/
/**	AttackEnable (PromotionInfos)	05/15/08										Xienwolf	**/
/**																								**/
/**									Blocks the UnitInfo Flag									**/
/*************************************************************************************************/
    if (isAllowAttacks())
    {
        return false;
    }
/*************************************************************************************************/
/**	AttackEnable (PromotionInfos)				END												**/
/*************************************************************************************************/

	return m_pUnitInfo->isOnlyDefensive();
}


bool CvUnit::isNoCapture() const
{

//FfH: Added by Kael 10/25/2007
/*************************************************************************************************/
/**	CannotCapture (PromotionInfos)	05/15/08										Xienwolf	**/
/**																								**/
/**									Simulates the UnitInfo Flag									**/
/*************************************************************************************************/
/**								---- Start Original Code ----
    if (isHiddenNationality())
								----  End Original Code  ----									**/
    if (isHiddenNationality() || isCannotCapture())
/*************************************************************************************************/
/**	CannotCapture (PromotionInfos)				END												**/
/*************************************************************************************************/
    {
        return true;
    }
//FfH: End Add

	return m_pUnitInfo->isNoCapture();
}


bool CvUnit::isRivalTerritory() const
{
/*************************************************************************************************/
/**	Rivals (PromotionInfos)			05/15/08										Xienwolf	**/
/**																								**/
/**							Blocks or Simulates the UnitInfo Flag								**/
/*************************************************************************************************/
    if (isRivalTerritoryBlock())
    {
        return false;
    }
    if (isRivalTerritoryExplore())
    {
        return true;
    }
/*************************************************************************************************/
/**	Rivals (PromotionInfos)		    			END												**/
/*************************************************************************************************/
	return m_pUnitInfo->isRivalTerritory();
}


bool CvUnit::isMilitaryHappiness() const
{
/*************************************************************************************************/
/**	No Reveal (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**							Blocks or Simulates the UnitInfo Flag								**/
/*************************************************************************************************/
    if (isCityNoHappy())
    {
        return false;
    }
    if (isCityHappy())
    {
        return true;
    }
/*************************************************************************************************/
/**	MilHappy (PromotionInfos)					END												**/
/*************************************************************************************************/
	return m_pUnitInfo->isMilitaryHappiness();
}


bool CvUnit::isInvestigate() const
{
/*************************************************************************************************/
/**	CitySpy (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**									Simulates the UnitInfo Flag									**/
/*************************************************************************************************/
    if (isCitySpy())
    {
        return true;
    }
/*************************************************************************************************/
/**	CitySpy (PromotionInfos)					END												**/
/*************************************************************************************************/
	return m_pUnitInfo->isInvestigate();
}


bool CvUnit::isCounterSpy() const
{
	return m_pUnitInfo->isCounterSpy();
}


bool CvUnit::isSpy() const
{
	return m_pUnitInfo->isSpy();
}


bool CvUnit::isFound() const
{
	return m_pUnitInfo->isFound();
}


bool CvUnit::isGoldenAge() const
{
	if (isDelayedDeath())
	{
		return false;
	}
/*************************************************************************************************/
/**	Goldie (PromotionInfos)			05/15/08										Xienwolf	**/
/**									Simulates the UnitInfo Flag									**/
/**		AI Doesn't seem to realize Unit is capable of this.  Or doesn't think it worthwhile		**/
/*************************************************************************************************/
	if (isStartGoldenAge())
	{
		return true;
	}
/*************************************************************************************************/
/**	Goldie (PromotionInfos)						END												**/
/*************************************************************************************************/
	return m_pUnitInfo->isGoldenAge();
}

bool CvUnit::canCoexistWithEnemyUnit(TeamTypes eTeam) const
{
	if (NO_TEAM == eTeam)
	{
		if(alwaysInvisible())
		{
			return true;
		}

		return false;
	}

	if(isInvisible(eTeam, false))
	{
		return true;
	}

	return false;
}

bool CvUnit::isFighting() const
{
	return (getCombatUnit() != NULL);
}


bool CvUnit::isAttacking() const
{
	return (getAttackPlot() != NULL && !isDelayedDeath());
}


bool CvUnit::isDefending() const
{
	return (isFighting() && !isAttacking());
}


bool CvUnit::isCombat() const
{
	return (isFighting() || isAttacking());
}


int CvUnit::maxHitPoints() const
{
	return GC.getMAX_HIT_POINTS();
}


int CvUnit::currHitPoints()	const
{
	return (maxHitPoints() - getDamage());
}


bool CvUnit::isHurt() const
{
	return (getDamage() > 0);
}


bool CvUnit::isDead() const
{
	return (getDamage() >= maxHitPoints());
}


void CvUnit::setBaseCombatStr(int iCombat)
{
	m_iBaseCombat = iCombat;
}

int CvUnit::baseCombatStr() const
{

//FfH Damage Types: Modified by Kael 10/26/2007
//    return m_iBaseCombat;
    return m_iBaseCombat + m_iTotalDamageTypeCombat;
//FfH: End Add

}

//FfH Defense Str: Added by Kael 10/26/2007
void CvUnit::setBaseCombatStrDefense(int iCombat)
{
	m_iBaseCombatDefense = iCombat;
}

int CvUnit::baseCombatStrDefense() const
{
    return m_iBaseCombatDefense + m_iTotalDamageTypeCombat;
}
//FfH: End Add

// maxCombatStr can be called in four different configurations
//		pPlot == NULL, pAttacker == NULL for combat when this is the attacker
//		pPlot valid, pAttacker valid for combat when this is the defender
//		pPlot valid, pAttacker == NULL (new case), when this is the defender, attacker unknown
//		pPlot valid, pAttacker == this (new case), when the defender is unknown, but we want to calc approx str
//			note, in this last case, it is expected pCombatDetails == NULL, it does not have to be, but some
//			values may be unexpectedly reversed in this case (iModifierTotal will be the negative sum)
int CvUnit::maxCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
{
	int iCombat;

//FfH Damage Types: Added by Kael 09/02/2007
    const CvUnit* pDefender = NULL;
    if (pPlot == NULL)
    {
        if (pAttacker != NULL)
        {
            pDefender = pAttacker;
            pAttacker = NULL;
        }
    }
//FfH: End Add

	FAssertMsg((pPlot == NULL) || (pPlot->getTerrainType() != NO_TERRAIN), "(pPlot == NULL) || (pPlot->getTerrainType() is not expected to be equal with NO_TERRAIN)");

	// handle our new special case
	const	CvPlot*	pAttackedPlot = NULL;
	bool	bAttackingUnknownDefender = false;
	if (pAttacker == this)
	{
		bAttackingUnknownDefender = true;
		pAttackedPlot = pPlot;

		// reset these values, we will fiddle with them below
		pPlot = NULL;
		pAttacker = NULL;
	}
	// otherwise, attack plot is the plot of us (the defender)
	else if (pAttacker != NULL)
	{
		pAttackedPlot = plot();
	}

	if (pCombatDetails != NULL)
	{
		pCombatDetails->iExtraCombatPercent = 0;
		pCombatDetails->iAnimalCombatModifierTA = 0;
		pCombatDetails->iAIAnimalCombatModifierTA = 0;
		pCombatDetails->iAnimalCombatModifierAA = 0;
		pCombatDetails->iAIAnimalCombatModifierAA = 0;
		pCombatDetails->iBarbarianCombatModifierTB = 0;
		pCombatDetails->iAIBarbarianCombatModifierTB = 0;
		pCombatDetails->iBarbarianCombatModifierAB = 0;
		pCombatDetails->iAIBarbarianCombatModifierAB = 0;
		pCombatDetails->iPlotDefenseModifier = 0;
		pCombatDetails->iFortifyModifier = 0;
		pCombatDetails->iCityDefenseModifier = 0;
		pCombatDetails->iHillsAttackModifier = 0;
		pCombatDetails->iHillsDefenseModifier = 0;
		pCombatDetails->iFeatureAttackModifier = 0;
		pCombatDetails->iFeatureDefenseModifier = 0;
		pCombatDetails->iTerrainAttackModifier = 0;
		pCombatDetails->iTerrainDefenseModifier = 0;
		pCombatDetails->iCityAttackModifier = 0;
		pCombatDetails->iDomainDefenseModifier = 0;
		pCombatDetails->iCityBarbarianDefenseModifier = 0;
		pCombatDetails->iClassDefenseModifier = 0;
		pCombatDetails->iClassAttackModifier = 0;
		pCombatDetails->iCombatModifierA = 0;
		pCombatDetails->iCombatModifierT = 0;
		pCombatDetails->iDomainModifierA = 0;
		pCombatDetails->iDomainModifierT = 0;
		pCombatDetails->iAnimalCombatModifierA = 0;
		pCombatDetails->iAnimalCombatModifierT = 0;
		pCombatDetails->iRiverAttackModifier = 0;
		pCombatDetails->iAmphibAttackModifier = 0;
		pCombatDetails->iKamikazeModifier = 0;
		pCombatDetails->iModifierTotal = 0;
		pCombatDetails->iBaseCombatStr = 0;
		pCombatDetails->iCombat = 0;
		pCombatDetails->iMaxCombatStr = 0;
		pCombatDetails->iCurrHitPoints = 0;
		pCombatDetails->iMaxHitPoints = 0;
		pCombatDetails->iCurrCombatStr = 0;
		pCombatDetails->eOwner = getVisualOwner();
		pCombatDetails->sUnitName = getName().GetCString();
	}

//FfH Defense Str: Modified by Kael 08/18/2007
//	if (baseCombatStr() == 0)
//	{
//		return 0;
//	}
    int iStr;
    if ((pAttacker == NULL && pPlot == NULL) || pAttacker == this)
    {
        iStr = baseCombatStr();
    }
    else
    {
        iStr = baseCombatStrDefense();
    }

	if (iStr == 0)
	{
		return 0;
	}
//FfH: End Modify

	int iModifier = 0;
	int iExtraModifier;

	iExtraModifier = getExtraCombatPercent();
	iModifier += iExtraModifier;
	if (pCombatDetails != NULL)
	{
		pCombatDetails->iExtraCombatPercent = iExtraModifier;
	}

	// do modifiers for animals and barbarians (leaving these out for bAttackingUnknownDefender case)
	if (pAttacker != NULL)
	{
		if (isAnimal())
		{
			if (pAttacker->isHuman())
			{
				iExtraModifier = GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAnimalCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAnimalCombatModifierTA = iExtraModifier;
				}
			}
			else
			{
				iExtraModifier = GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIAnimalCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAIAnimalCombatModifierTA = iExtraModifier;
				}
			}
		}

		if (pAttacker->isAnimal())
		{
			if (isHuman())
			{
				iExtraModifier = -GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAnimalCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAnimalCombatModifierAA = iExtraModifier;
				}
			}
			else
			{
				iExtraModifier = -GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIAnimalCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAIAnimalCombatModifierAA = iExtraModifier;
				}
			}
		}

		if (isBarbarian())
		{
			if (pAttacker->isHuman())
			{
				iExtraModifier = GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iBarbarianCombatModifierTB = iExtraModifier;
				}
			}
			else
			{
				iExtraModifier = GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIBarbarianCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAIBarbarianCombatModifierTB = iExtraModifier;
				}
			}
		}

		if (pAttacker->isBarbarian())
		{
			if (isHuman())
			{
				iExtraModifier = -GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getBarbarianCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iBarbarianCombatModifierAB = iExtraModifier;
				}
			}
			else
			{
				iExtraModifier = -GC.getHandicapInfo(GC.getGameINLINE().getHandicapType()).getAIBarbarianCombatModifier();
				iModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAIBarbarianCombatModifierTB = iExtraModifier;
				}
			}
		}
	}

	// add defensive bonuses (leaving these out for bAttackingUnknownDefender case)
	if (pPlot != NULL)
	{
		if (!noDefensiveBonus())
		{
			iExtraModifier = pPlot->defenseModifier(getTeam(), (pAttacker != NULL) ? pAttacker->ignoreBuildingDefense() : true);
			iModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iPlotDefenseModifier = iExtraModifier;
			}
		}

		iExtraModifier = fortifyModifier();
		iModifier += iExtraModifier;
		if (pCombatDetails != NULL)
		{
			pCombatDetails->iFortifyModifier = iExtraModifier;
		}

		if (pPlot->isCity(true, getTeam()))
		{
			iExtraModifier = cityDefenseModifier();
			iModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iCityDefenseModifier = iExtraModifier;
			}
		}

		if (pPlot->isHills())
		{
			iExtraModifier = hillsDefenseModifier();
			iModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iHillsDefenseModifier = iExtraModifier;
			}
		}

		if (pPlot->getFeatureType() != NO_FEATURE)
		{
			iExtraModifier = featureDefenseModifier(pPlot->getFeatureType());
			iModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iFeatureDefenseModifier = iExtraModifier;
			}
		}
		else
		{
			iExtraModifier = terrainDefenseModifier(pPlot->getTerrainType());
			iModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iTerrainDefenseModifier = iExtraModifier;
			}
		}
	}

	// if we are attacking to an plot with an unknown defender, the calc the modifier in reverse
	if (bAttackingUnknownDefender)
	{
		pAttacker = this;
	}

	// calc attacker bonueses
	if (pAttacker != NULL)
	{
		int iTempModifier = 0;

		if (pAttackedPlot->isCity(true, getTeam()))
		{
			iExtraModifier = -pAttacker->cityAttackModifier();
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iCityAttackModifier = iExtraModifier;
			}

			if (pAttacker->isBarbarian())
			{
				iExtraModifier = GC.getDefineINT("CITY_BARBARIAN_DEFENSE_MODIFIER");
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iCityBarbarianDefenseModifier = iExtraModifier;
				}
			}
		}

		if (pAttackedPlot->isHills())
		{
			iExtraModifier = -pAttacker->hillsAttackModifier();
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iHillsAttackModifier = iExtraModifier;
			}
		}

		if (pAttackedPlot->getFeatureType() != NO_FEATURE)
		{
			iExtraModifier = -pAttacker->featureAttackModifier(pAttackedPlot->getFeatureType());
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iFeatureAttackModifier = iExtraModifier;
			}
		}
		else
		{
			iExtraModifier = -pAttacker->terrainAttackModifier(pAttackedPlot->getTerrainType());
			iModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iTerrainAttackModifier = iExtraModifier;
			}
		}

		// only compute comparisions if we are the defender with a known attacker
		if (!bAttackingUnknownDefender)
		{
			FAssertMsg(pAttacker != this, "pAttacker is not expected to be equal with this");

//FfH Promotions: Added by Kael 08/13/2007
            for (int iJ=0;iJ<GC.getNumPromotionInfos();iJ++)
            {
                if ((isHasPromotion((PromotionTypes)iJ)) && (GC.getPromotionInfo((PromotionTypes)iJ).getPromotionCombatMod()>0))
                {
                    if (pAttacker->isHasPromotion((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iJ).getPromotionCombatType()))
                    {
                        iModifier += GC.getPromotionInfo((PromotionTypes)iJ).getPromotionCombatMod();
                    }
                }
                if ((pAttacker->isHasPromotion((PromotionTypes)iJ)) && (GC.getPromotionInfo((PromotionTypes)iJ).getPromotionCombatMod() > 0))
                {
                    if (isHasPromotion((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iJ).getPromotionCombatType()))
                    {
                        iModifier -= GC.getPromotionInfo((PromotionTypes)iJ).getPromotionCombatMod();
                    }
                }
            }
            if (GC.getGameINLINE().getGlobalCounter() * getCombatPercentGlobalCounter() / 100 != 0)
            {
                iModifier += GC.getGameINLINE().getGlobalCounter() * getCombatPercentGlobalCounter() / 100;
            }
            if (GC.getGameINLINE().getGlobalCounter() * pAttacker->getCombatPercentGlobalCounter() / 100 != 0)
            {
                iModifier -= GC.getGameINLINE().getGlobalCounter() * pAttacker->getCombatPercentGlobalCounter() / 100;
            }
//FfH: End Add

			iExtraModifier = unitClassDefenseModifier(pAttacker->getUnitClassType());
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iClassDefenseModifier = iExtraModifier;
			}

			iExtraModifier = -pAttacker->unitClassAttackModifier(getUnitClassType());
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iClassAttackModifier = iExtraModifier;
			}

			if (pAttacker->getUnitCombatType() != NO_UNITCOMBAT)
			{
				iExtraModifier = unitCombatModifier(pAttacker->getUnitCombatType());
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iCombatModifierA = iExtraModifier;
				}
			}
			if (getUnitCombatType() != NO_UNITCOMBAT)
			{
				iExtraModifier = -pAttacker->unitCombatModifier(getUnitCombatType());
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iCombatModifierT = iExtraModifier;
				}
			}

			iExtraModifier = domainModifier(pAttacker->getDomainType());
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iDomainModifierA = iExtraModifier;
			}

			iExtraModifier = -pAttacker->domainModifier(getDomainType());
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iDomainModifierT = iExtraModifier;
			}

			if (pAttacker->isAnimal())
			{
				iExtraModifier = animalCombatModifier();
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAnimalCombatModifierA = iExtraModifier;
				}
			}

			if (isAnimal())
			{
				iExtraModifier = -pAttacker->animalCombatModifier();
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAnimalCombatModifierT = iExtraModifier;
				}
			}
		}

		if (!(pAttacker->isRiver()))
		{
			if (pAttacker->plot()->isRiverCrossing(directionXY(pAttacker->plot(), pAttackedPlot)))
			{
				iExtraModifier = -GC.getRIVER_ATTACK_MODIFIER();
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iRiverAttackModifier = iExtraModifier;
				}
			}
		}

		if (!(pAttacker->isAmphib()))
		{
			if (!(pAttackedPlot->isWater()) && pAttacker->plot()->isWater())
			{
				iExtraModifier = -GC.getAMPHIB_ATTACK_MODIFIER();
				iTempModifier += iExtraModifier;
				if (pCombatDetails != NULL)
				{
					pCombatDetails->iAmphibAttackModifier = iExtraModifier;
				}
			}
		}

		if (pAttacker->getKamikazePercent() != 0)
		{
			iExtraModifier = pAttacker->getKamikazePercent();
			iTempModifier += iExtraModifier;
			if (pCombatDetails != NULL)
			{
				pCombatDetails->iKamikazeModifier = iExtraModifier;
			}
		}

		// if we are attacking an unknown defender, then use the reverse of the modifier
		if (bAttackingUnknownDefender)
		{
			iModifier -= iTempModifier;
		}
		else
		{
			iModifier += iTempModifier;
		}
	}

//FfH Defense Str: Modified by Kael 08/18/2007
//	if (pCombatDetails != NULL)
//	{
//		pCombatDetails->iModifierTotal = iModifier;
//		pCombatDetails->iBaseCombatStr = baseCombatStr();
//	}
//
//	if (iModifier > 0)
//	{
//		iCombat = (baseCombatStr() * (iModifier + 100));
//	}
//	else
//	{
//		iCombat = ((baseCombatStr() * 10000) / (100 - iModifier));
//  }
    if (pCombatDetails != NULL)
    {
        pCombatDetails->iModifierTotal = iModifier;
        pCombatDetails->iBaseCombatStr = iStr;
    }

    iStr *= 100;
    if (pAttacker != NULL)
    {
        for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
        {
            if (getDamageTypeCombat((DamageTypes) iI) != 0)
            {
                if (pAttacker->getDamageTypeResist((DamageTypes) iI) != 0)
                {
                    iStr -= getDamageTypeCombat((DamageTypes) iI) * 100;
                    iStr += getDamageTypeCombat((DamageTypes) iI) * (100 - pAttacker->getDamageTypeResist((DamageTypes) iI));
                }
            }
        }
    }
    if (pDefender != NULL)
    {
        for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
        {
            if (getDamageTypeCombat((DamageTypes) iI) != 0)
            {
                if (pDefender->getDamageTypeResist((DamageTypes) iI) != 0)
                {
                    iStr -= getDamageTypeCombat((DamageTypes) iI) * 100;
                    iStr += getDamageTypeCombat((DamageTypes) iI) * (100 - pDefender->getDamageTypeResist((DamageTypes) iI));
                }
            }
        }
    }

    if (iModifier > 0)
    {
        iCombat = (iStr * (iModifier + 100)) / 100;
    }
    else
    {
        iCombat = ((iStr * 100) / (100 - iModifier));
    }
//FfH: End Modify

	if (pCombatDetails != NULL)
	{
		pCombatDetails->iCombat = iCombat;
		pCombatDetails->iMaxCombatStr = std::max(1, iCombat);
		pCombatDetails->iCurrHitPoints = currHitPoints();
		pCombatDetails->iMaxHitPoints = maxHitPoints();
		pCombatDetails->iCurrCombatStr = ((pCombatDetails->iMaxCombatStr * pCombatDetails->iCurrHitPoints) / pCombatDetails->iMaxHitPoints);
	}

	return std::max(1, iCombat);
}


int CvUnit::currCombatStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
{
	return ((maxCombatStr(pPlot, pAttacker, pCombatDetails) * currHitPoints()) / maxHitPoints());
}


int CvUnit::currFirepower(const CvPlot* pPlot, const CvUnit* pAttacker) const
{
	return ((maxCombatStr(pPlot, pAttacker) + currCombatStr(pPlot, pAttacker) + 1) / 2);
}

// this nomalizes str by firepower, useful for quick odds calcs
// the effect is that a damaged unit will have an effective str lowered by firepower/maxFirepower
// doing the algebra, this means we mulitply by 1/2(1 + currHP)/maxHP = (maxHP + currHP) / (2 * maxHP)
int CvUnit::currEffectiveStr(const CvPlot* pPlot, const CvUnit* pAttacker, CombatDetails* pCombatDetails) const
{
	int currStr = currCombatStr(pPlot, pAttacker, pCombatDetails);

	currStr *= (maxHitPoints() + currHitPoints());
	currStr /= (2 * maxHitPoints());

	return currStr;
}

float CvUnit::maxCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const
{
	return (((float)(maxCombatStr(pPlot, pAttacker))) / 100.0f);
}


float CvUnit::currCombatStrFloat(const CvPlot* pPlot, const CvUnit* pAttacker) const
{
	return (((float)(currCombatStr(pPlot, pAttacker))) / 100.0f);
}


bool CvUnit::canFight() const
{

//FfH: Modified by Kael 10/31/2007
//	return (baseCombatStr() > 0);
    if (baseCombatStr() == 0 && baseCombatStrDefense() == 0)
    {
        return false;
    }
	return true;
//FfH: End Modify

}


bool CvUnit::canAttack() const
{
	if (!canFight())
	{
		return false;
	}

	if (isOnlyDefensive())
	{
		return false;
	}

//FfH: Added by Kael 10/31/2007
    if (baseCombatStr() == 0)
    {
        return false;
    }
//FfH: End Add

	return true;
}


bool CvUnit::canDefend(const CvPlot* pPlot) const
{
	if (pPlot == NULL)
	{
		pPlot = plot();
	}

	if (!canFight())
	{
		return false;
	}

	if (!pPlot->isValidDomainForAction(*this))
	{
		if (GC.getDefineINT("LAND_UNITS_CAN_ATTACK_WATER_CITIES") == 0)
		{
			return false;
		}
	}

//FfH: Added by Kael 10/31/2007
    if (baseCombatStrDefense() == 0)
    {
        return false;
    }
//FfH: End Add

	return true;
}


bool CvUnit::canSiege(TeamTypes eTeam) const
{
	if (!canDefend())
	{
		return false;
	}

	if (!isEnemy(eTeam))
	{
		return false;
	}

	if (!isNeverInvisible())
	{
		return false;
	}

	return true;
}


int CvUnit::airBaseCombatStr() const
{
	return m_pUnitInfo->getAirCombat();
}


int CvUnit::airMaxCombatStr(const CvUnit* pOther) const
{
	int iModifier;
	int iCombat;

	if (airBaseCombatStr() == 0)
	{
		return 0;
	}

	iModifier = getExtraCombatPercent();

	if (getKamikazePercent() != 0)
	{
		iModifier += getKamikazePercent();
	}

	if (getExtraCombatPercent() != 0)
	{
		iModifier += getExtraCombatPercent();
	}

	if (NULL != pOther)
	{
		if (pOther->getUnitCombatType() != NO_UNITCOMBAT)
		{
			iModifier += unitCombatModifier(pOther->getUnitCombatType());
		}

		iModifier += domainModifier(pOther->getDomainType());

		if (pOther->isAnimal())
		{
			iModifier += animalCombatModifier();
		}
	}

	if (iModifier > 0)
	{
		iCombat = (airBaseCombatStr() * (iModifier + 100));
	}
	else
	{
		iCombat = ((airBaseCombatStr() * 10000) / (100 - iModifier));
	}

	return std::max(1, iCombat);
}


int CvUnit::airCurrCombatStr(const CvUnit* pOther) const
{
	return ((airMaxCombatStr(pOther) * currHitPoints()) / maxHitPoints());
}


float CvUnit::airMaxCombatStrFloat(const CvUnit* pOther) const
{
	return (((float)(airMaxCombatStr(pOther))) / 100.0f);
}


float CvUnit::airCurrCombatStrFloat(const CvUnit* pOther) const
{
	return (((float)(airCurrCombatStr(pOther))) / 100.0f);
}


int CvUnit::combatLimit() const
{

//FfH: Modified by Kael 04/26/2008
//	return m_pUnitInfo->getCombatLimit();
    return m_iCombatLimit;
//FfH: End Modify

}


int CvUnit::airCombatLimit() const
{
	return m_pUnitInfo->getAirCombatLimit();
}


bool CvUnit::canAirAttack() const
{
	return (airBaseCombatStr() > 0);
}


bool CvUnit::canAirDefend(const CvPlot* pPlot) const
{
	if (pPlot == NULL)
	{
		pPlot = plot();
	}

	if (maxInterceptionProbability() == 0)
	{
		return false;
	}

	if (getDomainType() != DOMAIN_AIR)
	{
		if (!pPlot->isValidDomainForLocation(*this))
		{
			return false;
		}
	}

	return true;
}


int CvUnit::airCombatDamage(const CvUnit* pDefender) const
{
	CvCity* pCity;
	CvPlot* pPlot;
	int iOurStrength;
	int iTheirStrength;
	int iStrengthFactor;
	int iDamage;

	pPlot = pDefender->plot();

	iOurStrength = airCurrCombatStr(pDefender);
	FAssertMsg(iOurStrength > 0, "Air combat strength is expected to be greater than zero");
	iTheirStrength = pDefender->maxCombatStr(pPlot, this);

	iStrengthFactor = ((iOurStrength + iTheirStrength + 1) / 2);

	iDamage = std::max(1, ((GC.getDefineINT("AIR_COMBAT_DAMAGE") * (iOurStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor)));

	pCity = pPlot->getPlotCity();

	if (pCity != NULL)
	{
		iDamage *= std::max(0, (pCity->getAirModifier() + 100));
		iDamage /= 100;
	}

	return iDamage;
}


int CvUnit::rangeCombatDamage(const CvUnit* pDefender) const
{
	CvPlot* pPlot;
	int iOurStrength;
	int iTheirStrength;
	int iStrengthFactor;
	int iDamage;

	pPlot = pDefender->plot();

	iOurStrength = airCurrCombatStr(pDefender);
	FAssertMsg(iOurStrength > 0, "Combat strength is expected to be greater than zero");
	iTheirStrength = pDefender->maxCombatStr(pPlot, this);

	iStrengthFactor = ((iOurStrength + iTheirStrength + 1) / 2);

	iDamage = std::max(1, ((GC.getDefineINT("RANGE_COMBAT_DAMAGE") * (iOurStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor)));

	return iDamage;
}


CvUnit* CvUnit::bestInterceptor(const CvPlot* pPlot) const
{
	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	int iValue;
	int iBestValue;
	int iLoop;
	int iI;

	iBestValue = 0;
	pBestUnit = NULL;

	for (iI = 0; iI < MAX_PLAYERS; iI++)
	{
		if (GET_PLAYER((PlayerTypes)iI).isAlive())
		{
			if (isEnemy(GET_PLAYER((PlayerTypes)iI).getTeam()) && !isInvisible(GET_PLAYER((PlayerTypes)iI).getTeam(), false, false))
			{
				for(pLoopUnit = GET_PLAYER((PlayerTypes)iI).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER((PlayerTypes)iI).nextUnit(&iLoop))
				{
					if (pLoopUnit->canAirDefend())
					{
						if (!pLoopUnit->isMadeInterception())
						{
							if ((pLoopUnit->getDomainType() != DOMAIN_AIR) || !(pLoopUnit->hasMoved()))
							{
								if ((pLoopUnit->getDomainType() != DOMAIN_AIR) || (pLoopUnit->getGroup()->getActivityType() == ACTIVITY_INTERCEPT))
								{
									if (plotDistance(pLoopUnit->getX_INLINE(), pLoopUnit->getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) <= pLoopUnit->airRange())
									{
										iValue = pLoopUnit->currInterceptionProbability();

										if (iValue > iBestValue)
										{
											iBestValue = iValue;
											pBestUnit = pLoopUnit;
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	return pBestUnit;
}


CvUnit* CvUnit::bestSeaPillageInterceptor(const CvPlot* pPlot) const
{
	if (!pPlot->isWater())
	{
		return NULL;
	}

	CvUnit* pBestUnit = NULL;

	for (int iDX = -1; iDX <= 1; ++iDX)
	{
		for (int iDY = -1; iDY <= 1; ++iDY)
		{
			CvPlot* pLoopPlot = plotXY(pPlot->getX_INLINE(), pPlot->getY_INLINE(), iDX, iDY);

			if (NULL != pLoopPlot)
			{
				CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();

				while (NULL != pUnitNode)
				{
					CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
					pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);

					if (NULL != pLoopUnit)
					{
						if (pLoopUnit->area() == pPlot->area())
						{
							if (!pLoopUnit->isInvisible(getTeam(), false))
							{
								if (isEnemy(pLoopUnit->getTeam()))
								{
									if (DOMAIN_SEA == pLoopUnit->getDomainType())
									{
										if (ACTIVITY_PATROL == pLoopUnit->getGroup()->getActivityType())
										{
											if (NULL == pBestUnit || pLoopUnit->isBetterDefenderThan(pBestUnit, this))
											{
												pBestUnit = pLoopUnit;
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}
	}

	return pBestUnit;
}


bool CvUnit::isAutomated() const
{
	return getGroup()->isAutomated();
}


bool CvUnit::isWaiting() const
{
	return getGroup()->isWaiting();
}


bool CvUnit::isFortifyable() const
{
	if (!canFight() || noDefensiveBonus() || ((getDomainType() != DOMAIN_LAND) && (getDomainType() != DOMAIN_IMMOBILE)))
	{
		return false;
	}

	return true;
}


int CvUnit::fortifyModifier() const
{
	if (!isFortifyable())
	{
		return 0;
	}

//FfH: Modified by Kael 10/26/2007
//	return (getFortifyTurns() * GC.getFORTIFY_MODIFIER_PER_TURN());
   	int i = getFortifyTurns() * GC.getFORTIFY_MODIFIER_PER_TURN();
    if (isDoubleFortifyBonus())
    {
        i *= 2;
    }
    return i;
//FfH: End Modify

}


int CvUnit::experienceNeeded() const
{
	// Use python to determine pillage amounts...
	int iExperienceNeeded;
	long lExperienceNeeded;

	lExperienceNeeded = 0;
	iExperienceNeeded = 0;

	CyArgsList argsList;
	argsList.add(getLevel());	// pass in the units level
	argsList.add(getOwner());	// pass in the units

	gDLL->getPythonIFace()->callFunction(PYGameModule, "getExperienceNeeded", argsList.makeFunctionArgs(),&lExperienceNeeded);

	iExperienceNeeded = (int)lExperienceNeeded;

	return iExperienceNeeded;
}


int CvUnit::attackXPValue() const
{
	return m_pUnitInfo->getXPValueAttack();
}


int CvUnit::defenseXPValue() const
{
	return m_pUnitInfo->getXPValueDefense();
}


int CvUnit::maxXPValue() const
{
	int iMaxValue;

	iMaxValue = MAX_INT;

	if (isAnimal())
	{
		iMaxValue = std::min(iMaxValue, GC.getDefineINT("ANIMAL_MAX_XP_VALUE"));
	}

	if (isBarbarian())
	{
		iMaxValue = std::min(iMaxValue, GC.getDefineINT("BARBARIAN_MAX_XP_VALUE"));
	}

	return iMaxValue;
}


int CvUnit::firstStrikes() const
{
	return std::max(0, (m_pUnitInfo->getFirstStrikes() + getExtraFirstStrikes()));
}


int CvUnit::chanceFirstStrikes() const
{
	return std::max(0, (m_pUnitInfo->getChanceFirstStrikes() + getExtraChanceFirstStrikes()));
}


int CvUnit::maxFirstStrikes() const
{
	return (firstStrikes() + chanceFirstStrikes());
}


bool CvUnit::isRanged() const
{
	int i;
	CvUnitInfo * pkUnitInfo = &getUnitInfo();
	for ( i = 0; i < pkUnitInfo->getGroupDefinitions(); i++ )
	{
		if ( !getArtInfo(i, GET_PLAYER(getOwnerINLINE()).getCurrentEra())->getActAsRanged() )
		{
			return false;
		}
	}
	return true;
}


bool CvUnit::alwaysInvisible() const
{
	return m_pUnitInfo->isInvisible();
}


bool CvUnit::immuneToFirstStrikes() const
{
/*************************************************************************************************/
/**	FirstStrikeable (PromotionInfos)05/15/08										Xienwolf	**/
/**																								**/
/**									Simulates the UnitInfo Flag									**/
/*************************************************************************************************/
    if (isFirstStrikeVulnerable())
    {
        return false;
    }
/*************************************************************************************************/
/**	FirstStrikeable (PromotionInfos)			END												**/
/*************************************************************************************************/
	return (m_pUnitInfo->isFirstStrikeImmune() || (getImmuneToFirstStrikesCount() > 0));
}


bool CvUnit::noDefensiveBonus() const
{
/*************************************************************************************************/
/**	DefenseBlock (PromotionInfos)	05/15/08										Xienwolf	**/
/**									Simulates the UnitInfo Flag									**/
/**																								**/
/**	DefenseEnable (PromotionInfos)	05/15/08										Xienwolf	**/
/**									Blocks the UnitInfo Flag									**/
/*************************************************************************************************/
    if (isNoDefenseBonus())
    {
        return true;
    }
    if (isAllowDefenseBonuses())
    {
        return false;
    }
/*************************************************************************************************/
/**	DefenseBlock (PromotionInfos)					END												**/
/**	DefenseEnable (PromotionInfos)					END												**/
/*************************************************************************************************/
    return m_pUnitInfo->isNoDefensiveBonus();
}


bool CvUnit::ignoreBuildingDefense() const
{

//FfH: Modifed by Kael 11/17/2007
//	return m_pUnitInfo->isIgnoreBuildingDefense();
    if (m_pUnitInfo->isIgnoreBuildingDefense())
    {
        return true;
    }
    return m_bIgnoreBuildingDefense;
//FfH: End Modify

}


bool CvUnit::canMoveImpassable() const
{

//FfH Flying: Added by Kael 07/30/2007
    if (isFlying())
    {
        return true;
    }
//FfH: End Add
/*************************************************************************************************/
/**	ImpassMove (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**									Simulates the UnitInfo Flag									**/
/*************************************************************************************************/
    if (isMoveImpassable())
    {
        return true;
    }
/*************************************************************************************************/
/**	ImpassMove (PromotionInfos)					END												**/
/*************************************************************************************************/

	return m_pUnitInfo->isCanMoveImpassable();
}

bool CvUnit::canMoveAllTerrain() const
{

//FfH Flying: Added by Kael 07/30/2007
    if (isFlying() || isWaterWalking())
    {
        return true;
    }
//FfH: End Add

	return m_pUnitInfo->isCanMoveAllTerrain();
}

bool CvUnit::flatMovementCost() const
{

//FfH Flying: Added by Kael 07/30/2007
    if (isFlying())
    {
        return true;
    }
//FfH: End Add
/*************************************************************************************************/
/**	No Reveal (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**									Simulates the UnitInfo Flag									**/
/*************************************************************************************************/
    if (isFlatMoveCost())
    {
        return true;
    }
/*************************************************************************************************/
/**	MoveConst (PromotionInfos)					END												**/
/*************************************************************************************************/

	return m_pUnitInfo->isFlatMovementCost();
}


bool CvUnit::ignoreTerrainCost() const
{

//FfH Flying: Added by Kael 07/30/2007
    if (isFlying())
    {
        return true;
    }
//FfH: End Add
/*************************************************************************************************/
/**	MoveBetter (PromotionInfos)		05/15/08										Xienwolf	**/
/**																								**/
/**								Simulates the UnitInfo Flag										**/
/*************************************************************************************************/
    if (isIgnoreTerrainCosts())
    {
        return true;
    }
/*************************************************************************************************/
/**	MoveBetter (PromotionInfos)					END												**/
/*************************************************************************************************/

	return m_pUnitInfo->isIgnoreTerrainCost();
}


bool CvUnit::isNeverInvisible() const
{
	return (!alwaysInvisible() && (getInvisibleType() == NO_INVISIBLE));
}


bool CvUnit::isInvisible(TeamTypes eTeam, bool bDebug, bool bCheckCargo) const
{
	if (bDebug && GC.getGameINLINE().isDebugMode())
	{
		return false;
	}

	if (getTeam() == eTeam)
	{
		return false;
	}

//FfH: Added by Kael 04/11/2008
    if (plot()->isCity())
    {
        if (getTeam() == plot()->getTeam())
        {
            return false;
        }
    }
    if (plot()->isOwned())
    {
        if (plot()->getTeam() != getTeam())
        {
            if (GET_PLAYER(plot()->getOwnerINLINE()).isSeeInvisible())
            {
                return false;
            }
        }
        if (plot()->getTeam() == getTeam())
        {
            if (GET_PLAYER(plot()->getOwnerINLINE()).isHideUnits())
            {
                return true;
            }
        }
    }
//FfH: End Add

	if (alwaysInvisible())
	{
		return true;
	}

	if (bCheckCargo && isCargo())
	{
		return true;
	}

	if (getInvisibleType() == NO_INVISIBLE)
	{
		return false;
	}

	return !(plot()->isInvisibleVisible(eTeam, getInvisibleType()));
}


bool CvUnit::isNukeImmune() const
{
	return m_pUnitInfo->isNukeImmune();
}


int CvUnit::maxInterceptionProbability() const
{
	return std::max(0, m_pUnitInfo->getInterceptionProbability() + getExtraIntercept());
}


int CvUnit::currInterceptionProbability() const
{
	if (getDomainType() != DOMAIN_AIR)
	{
		return maxInterceptionProbability();
	}
	else
	{
		return ((maxInterceptionProbability() * currHitPoints()) / maxHitPoints());
	}
}


int CvUnit::evasionProbability() const
{
	return std::max(0, m_pUnitInfo->getEvasionProbability() + getExtraEvasion());
}


int CvUnit::withdrawalProbability() const
{
	return std::max(0, (m_pUnitInfo->getWithdrawalProbability() + getExtraWithdrawal()));
}


int CvUnit::collateralDamage() const
{
	return std::max(0, (m_pUnitInfo->getCollateralDamage() + getExtraCollateralDamage()));
}


int CvUnit::collateralDamageLimit() const
{
	return std::max(0, ((m_pUnitInfo->getCollateralDamageLimit() * GC.getMAX_HIT_POINTS()) / 100));
}


int CvUnit::collateralDamageMaxUnits() const
{
	return std::max(0, m_pUnitInfo->getCollateralDamageMaxUnits());
}


int CvUnit::cityAttackModifier() const
{
	return (m_pUnitInfo->getCityAttackModifier() + getExtraCityAttackPercent());
}


int CvUnit::cityDefenseModifier() const
{
	return (m_pUnitInfo->getCityDefenseModifier() + getExtraCityDefensePercent());
}


int CvUnit::animalCombatModifier() const
{
	return m_pUnitInfo->getAnimalCombatModifier();
}


int CvUnit::hillsAttackModifier() const
{
	return (m_pUnitInfo->getHillsAttackModifier() + getExtraHillsAttackPercent());
}


int CvUnit::hillsDefenseModifier() const
{
	return (m_pUnitInfo->getHillsDefenseModifier() + getExtraHillsDefensePercent());
}


int CvUnit::terrainAttackModifier(TerrainTypes eTerrain) const
{
	FAssertMsg(eTerrain >= 0, "eTerrain is expected to be non-negative (invalid Index)");
	FAssertMsg(eTerrain < GC.getNumTerrainInfos(), "eTerrain is expected to be within maximum bounds (invalid Index)");
	return (m_pUnitInfo->getTerrainAttackModifier(eTerrain) + getExtraTerrainAttackPercent(eTerrain));
}


int CvUnit::terrainDefenseModifier(TerrainTypes eTerrain) const
{
	FAssertMsg(eTerrain >= 0, "eTerrain is expected to be non-negative (invalid Index)");
	FAssertMsg(eTerrain < GC.getNumTerrainInfos(), "eTerrain is expected to be within maximum bounds (invalid Index)");
	return (m_pUnitInfo->getTerrainDefenseModifier(eTerrain) + getExtraTerrainDefensePercent(eTerrain));
}


int CvUnit::featureAttackModifier(FeatureTypes eFeature) const
{
	FAssertMsg(eFeature >= 0, "eFeature is expected to be non-negative (invalid Index)");
	FAssertMsg(eFeature < GC.getNumFeatureInfos(), "eFeature is expected to be within maximum bounds (invalid Index)");
	return (m_pUnitInfo->getFeatureAttackModifier(eFeature) + getExtraFeatureAttackPercent(eFeature));
}

int CvUnit::featureDefenseModifier(FeatureTypes eFeature) const
{
	FAssertMsg(eFeature >= 0, "eFeature is expected to be non-negative (invalid Index)");
	FAssertMsg(eFeature < GC.getNumFeatureInfos(), "eFeature is expected to be within maximum bounds (invalid Index)");
	return (m_pUnitInfo->getFeatureDefenseModifier(eFeature) + getExtraFeatureDefensePercent(eFeature));
}

int CvUnit::unitClassAttackModifier(UnitClassTypes eUnitClass) const
{
	FAssertMsg(eUnitClass >= 0, "eUnitClass is expected to be non-negative (invalid Index)");
	FAssertMsg(eUnitClass < GC.getNumUnitClassInfos(), "eUnitClass is expected to be within maximum bounds (invalid Index)");
	return m_pUnitInfo->getUnitClassAttackModifier(eUnitClass);
}


int CvUnit::unitClassDefenseModifier(UnitClassTypes eUnitClass) const
{
	FAssertMsg(eUnitClass >= 0, "eUnitClass is expected to be non-negative (invalid Index)");
	FAssertMsg(eUnitClass < GC.getNumUnitClassInfos(), "eUnitClass is expected to be within maximum bounds (invalid Index)");
	return m_pUnitInfo->getUnitClassDefenseModifier(eUnitClass);
}


int CvUnit::unitCombatModifier(UnitCombatTypes eUnitCombat) const
{
	FAssertMsg(eUnitCombat >= 0, "eUnitCombat is expected to be non-negative (invalid Index)");
	FAssertMsg(eUnitCombat < GC.getNumUnitCombatInfos(), "eUnitCombat is expected to be within maximum bounds (invalid Index)");
	return (m_pUnitInfo->getUnitCombatModifier(eUnitCombat) + getExtraUnitCombatModifier(eUnitCombat));
}


int CvUnit::domainModifier(DomainTypes eDomain) const
{
	FAssertMsg(eDomain >= 0, "eDomain is expected to be non-negative (invalid Index)");
	FAssertMsg(eDomain < NUM_DOMAIN_TYPES, "eDomain is expected to be within maximum bounds (invalid Index)");
	return (m_pUnitInfo->getDomainModifier(eDomain) + getExtraDomainModifier(eDomain));
}


int CvUnit::bombardRate() const
{
	return (m_pUnitInfo->getBombardRate() + getExtraBombardRate());
}


int CvUnit::airBombBaseRate() const
{
	return m_pUnitInfo->getBombRate();
}


int CvUnit::airBombCurrRate() const
{
	return ((airBombBaseRate() * currHitPoints()) / maxHitPoints());
}


SpecialUnitTypes CvUnit::specialCargo() const
{
	return ((SpecialUnitTypes)(m_pUnitInfo->getSpecialCargo()));
}


DomainTypes CvUnit::domainCargo() const
{
	return ((DomainTypes)(m_pUnitInfo->getDomainCargo()));
}


int CvUnit::cargoSpace() const
{
	return m_iCargoCapacity;
}

void CvUnit::changeCargoSpace(int iChange)
{
	if (iChange != 0)
	{
		m_iCargoCapacity += iChange;
		FAssert(m_iCargoCapacity >= 0);
		setInfoBarDirty(true);
	}
}

bool CvUnit::isFull() const
{
	return (getCargo() >= cargoSpace());
}


int CvUnit::cargoSpaceAvailable(SpecialUnitTypes eSpecialCargo, DomainTypes eDomainCargo) const
{
	if (specialCargo() != NO_SPECIALUNIT)
	{
		if (specialCargo() != eSpecialCargo)
		{
			return 0;
		}
	}

	if (domainCargo() != NO_DOMAIN)
	{
		if (domainCargo() != eDomainCargo)
		{
			return 0;
		}
	}

	return std::max(0, (cargoSpace() - getCargo()));
}


bool CvUnit::hasCargo() const
{
	return (getCargo() > 0);
}


bool CvUnit::canCargoAllMove() const
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;

	pPlot = plot();

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (pLoopUnit->getDomainType() == DOMAIN_LAND)
			{
				if (!(pLoopUnit->canMove()))
				{
					return false;
				}
			}
		}
	}

	return true;
}

bool CvUnit::canCargoEnterArea(TeamTypes eTeam, const CvArea* pArea, bool bIgnoreRightOfPassage) const
{
	CvPlot* pPlot = plot();

	CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (!pLoopUnit->canEnterArea(eTeam, pArea, bIgnoreRightOfPassage))
			{
				return false;
			}
		}
	}

	return true;
}

int CvUnit::getUnitAICargo(UnitAITypes eUnitAI) const
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pPlot;
	int iCount;

	iCount = 0;

	pPlot = plot();

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit->getTransportUnit() == this)
		{
			if (pLoopUnit->AI_getUnitAIType() == eUnitAI)
			{
				iCount++;
			}
		}
	}

	return iCount;
}


int CvUnit::getID() const
{
	return m_iID;
}


int CvUnit::getIndex() const
{
	return (getID() & FLTA_INDEX_MASK);
}


IDInfo CvUnit::getIDInfo() const
{
	IDInfo unit(getOwnerINLINE(), getID());
	return unit;
}


void CvUnit::setID(int iID)
{
	m_iID = iID;
}


int CvUnit::getGroupID() const
{
	return m_iGroupID;
}


bool CvUnit::isInGroup() const
{
	return(getGroupID() != FFreeList::INVALID_INDEX);
}


bool CvUnit::isGroupHead() const // XXX is this used???
{
	return (getGroup()->getHeadUnit() == this);
}


CvSelectionGroup* CvUnit::getGroup() const
{
	return GET_PLAYER(getOwnerINLINE()).getSelectionGroup(getGroupID());
}


bool CvUnit::canJoinGroup(const CvPlot* pPlot, CvSelectionGroup* pSelectionGroup) const
{
	CvUnit* pHeadUnit;

	// do not allow someone to join a group that is about to be split apart
	// this prevents a case of a never-ending turn
	if (pSelectionGroup->AI_isForceSeparate())
	{
		return false;
	}

	if (pSelectionGroup->getOwnerINLINE() == NO_PLAYER)
	{
		pHeadUnit = pSelectionGroup->getHeadUnit();

		if (pHeadUnit != NULL)
		{
			if (pHeadUnit->getOwnerINLINE() != getOwnerINLINE())
			{
				return false;
			}
		}
	}
	else
	{
		if (pSelectionGroup->getOwnerINLINE() != getOwnerINLINE())
		{
			return false;
		}
	}

	if (pSelectionGroup->getNumUnits() > 0)
	{
		if (!(pSelectionGroup->atPlot(pPlot)))
		{
			return false;
		}

		if (pSelectionGroup->getDomainType() != getDomainType())
		{
			return false;
		}

//FfH: Added by Kael 11/14/2007
        if (isHiddenNationality())
        {
            return false;
        }
        pHeadUnit = pSelectionGroup->getHeadUnit();
        if (pHeadUnit->isHiddenNationality())
        {
            if (pHeadUnit != NULL)
            {
                return false;
            }
		}
//FfH: End Add

	}

	return true;
}


void CvUnit::joinGroup(CvSelectionGroup* pSelectionGroup, bool bRemoveSelected, bool bRejoin)
{
	CvSelectionGroup* pOldSelectionGroup;
	CvSelectionGroup* pNewSelectionGroup;
	CvPlot* pPlot;

	pOldSelectionGroup = GET_PLAYER(getOwnerINLINE()).getSelectionGroup(getGroupID());

	if ((pSelectionGroup != pOldSelectionGroup) || (pOldSelectionGroup == NULL))
	{
		pPlot = plot();

		if (pSelectionGroup != NULL)
		{
			pNewSelectionGroup = pSelectionGroup;
		}
		else
		{
			if (bRejoin)
			{
				pNewSelectionGroup = GET_PLAYER(getOwnerINLINE()).addSelectionGroup();
				pNewSelectionGroup->init(pNewSelectionGroup->getID(), getOwnerINLINE());
			}
			else
			{
				pNewSelectionGroup = NULL;
			}
		}

		if ((pNewSelectionGroup == NULL) || canJoinGroup(plot(), pNewSelectionGroup))
		{
			if (pOldSelectionGroup != NULL)
			{
				bool bWasHead = false;
				if (!isHuman())
				{
					if (pOldSelectionGroup->getNumUnits() > 1)
					{
						if (pOldSelectionGroup->getHeadUnit() == this)
						{
							bWasHead = true;
						}
					}
				}

				pOldSelectionGroup->removeUnit(this);

				// if we were the head, if the head unitAI changed, then force the group to separate (non-humans)
				if (bWasHead)
				{
					FAssert(pOldSelectionGroup->getHeadUnit() != NULL);
					if (pOldSelectionGroup->getHeadUnit()->AI_getUnitAIType() != AI_getUnitAIType())
					{
						pOldSelectionGroup->AI_makeForceSeparate();
					}
				}
			}

			if ((pNewSelectionGroup != NULL) && pNewSelectionGroup->addUnit(this, false))
			{
				m_iGroupID = pNewSelectionGroup->getID();
			}
			else
			{
				m_iGroupID = FFreeList::INVALID_INDEX;
			}

			if (getGroup() != NULL)
			{
				if (getGroup()->getNumUnits() > 1)
				{
					getGroup()->setActivityType(ACTIVITY_AWAKE);
				}
				else
				{
					GET_PLAYER(getOwnerINLINE()).updateGroupCycle(this);
				}
			}

			if (getTeam() == GC.getGameINLINE().getActiveTeam())
			{
				if (pPlot != NULL)
				{
					pPlot->setFlagDirty(true);
				}
			}

			if (pPlot == gDLL->getInterfaceIFace()->getSelectionPlot())
			{
				gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
			}
		}

		if (bRemoveSelected)
		{
			if (IsSelected())
			{
				gDLL->getInterfaceIFace()->removeFromSelectionList(this);
			}
		}
	}
}


int CvUnit::getHotKeyNumber()
{
	return m_iHotKeyNumber;
}


void CvUnit::setHotKeyNumber(int iNewValue)
{
	CvUnit* pLoopUnit;
	int iLoop;

	FAssert(getOwnerINLINE() != NO_PLAYER);

	if (getHotKeyNumber() != iNewValue)
	{
		if (iNewValue != -1)
		{
			for(pLoopUnit = GET_PLAYER(getOwnerINLINE()).firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = GET_PLAYER(getOwnerINLINE()).nextUnit(&iLoop))
			{
				if (pLoopUnit->getHotKeyNumber() == iNewValue)
				{
					pLoopUnit->setHotKeyNumber(-1);
				}
			}
		}

		m_iHotKeyNumber = iNewValue;

		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
		}
	}
}


int CvUnit::getX() const
{
	return m_iX;
}


int CvUnit::getY() const
{
	return m_iY;
}


void CvUnit::setXY(int iX, int iY, bool bGroup, bool bUpdate, bool bShow, bool bCheckPlotVisible)
{
	CLLNode<IDInfo>* pUnitNode;
	CvCity* pOldCity;
	CvCity* pNewCity;
	CvCity* pWorkingCity;
	CvUnit* pTransportUnit;
	CvUnit* pLoopUnit;
	CvPlot* pOldPlot;
	CvPlot* pNewPlot;
	CvPlot* pLoopPlot;
	CLinkList<IDInfo> oldUnits;
	ActivityTypes eOldActivityType;
	int iI;

	// OOS!! Temporary for Out-of-Sync madness debugging...
	if (GC.getLogging())
	{
		if (gDLL->getChtLvl() > 0)
		{
			char szOut[1024];
			sprintf(szOut, "Player %d Unit %d (%S's %S) moving from %d:%d to %d:%d\n", getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getNameKey(), getName().GetCString(), getX_INLINE(), getY_INLINE(), iX, iY);
			gDLL->messageControlLog(szOut);
		}
	}

	FAssert(!at(iX, iY));
	FAssert(!isFighting());
	FAssert((iX == INVALID_PLOT_COORD) || (GC.getMapINLINE().plotINLINE(iX, iY)->getX_INLINE() == iX));
	FAssert((iY == INVALID_PLOT_COORD) || (GC.getMapINLINE().plotINLINE(iX, iY)->getY_INLINE() == iY));

	if (getGroup() != NULL)
	{
		eOldActivityType = getGroup()->getActivityType();
	}
	else
	{
		eOldActivityType = NO_ACTIVITY;
	}

	setBlockading(false);

	if (!bGroup || isCargo())
	{
		joinGroup(NULL, true);
		bShow = false;
	}

	pNewPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	if (pNewPlot != NULL)
	{
		pTransportUnit = getTransportUnit();

		if (pTransportUnit != NULL)
		{
			if (!(pTransportUnit->atPlot(pNewPlot)))
			{
				setTransportUnit(NULL);
			}
		}

		if (canFight())
		{
			oldUnits.clear();

			pUnitNode = pNewPlot->headUnitNode();

			while (pUnitNode != NULL)
			{
				oldUnits.insertAtEnd(pUnitNode->m_data);
				pUnitNode = pNewPlot->nextUnitNode(pUnitNode);
			}

			pUnitNode = oldUnits.head();

			while (pUnitNode != NULL)
			{
				pLoopUnit = ::getUnit(pUnitNode->m_data);
				pUnitNode = oldUnits.next(pUnitNode);

				if (pLoopUnit != NULL)
				{
					if (isEnemy(pLoopUnit->getTeam(), pNewPlot) || pLoopUnit->isEnemy(getTeam()))
					{
						if (!pLoopUnit->canCoexistWithEnemyUnit(getTeam()))
						{
							if (NO_UNITCLASS == pLoopUnit->getUnitInfo().getUnitCaptureClassType() && pLoopUnit->canDefend(pNewPlot))
							{
								pLoopUnit->jumpToNearestValidPlot(); // can kill unit
							}
							else
							{

//FfH Hidden Nationality: Modified by Kael 08/27/2007
//								if (!m_pUnitInfo->isHiddenNationality() && !pLoopUnit->getUnitInfo().isHiddenNationality())
								if (!isHiddenNationality() && !pLoopUnit->isHiddenNationality())
//FfH: End Modify

								{
									GET_TEAM(pLoopUnit->getTeam()).changeWarWeariness(getTeam(), *pNewPlot, GC.getDefineINT("WW_UNIT_CAPTURED"));
									GET_TEAM(getTeam()).changeWarWeariness(pLoopUnit->getTeam(), *pNewPlot, GC.getDefineINT("WW_CAPTURED_UNIT"));
									GET_TEAM(getTeam()).AI_changeWarSuccess(pLoopUnit->getTeam(), GC.getDefineINT("WAR_SUCCESS_UNIT_CAPTURING"));
								}

//FfH: Modified by Kael 12/30/2207
//								if (!isNoCapture())
//								{
//									pLoopUnit->setCapturingPlayer(getOwnerINLINE());
//								}
								if (!isNoCapture() || GC.getUnitInfo((UnitTypes)pLoopUnit->getUnitType()).getEquipmentPromotion() != NO_PROMOTION)
								{
								    if (!pLoopUnit->isHiddenNationality())
								    {
                                        pLoopUnit->setCapturingPlayer(getOwnerINLINE());
                                    }
								}
//FfH: End Modify

								pLoopUnit->kill(false, getOwnerINLINE());
							}
						}
					}
				}
			}
		}

		if (pNewPlot->isGoody(getTeam()))
		{
			GET_PLAYER(getOwnerINLINE()).doGoody(pNewPlot, this);
		}
	}

	pOldPlot = plot();

	if (pOldPlot != NULL)
	{
		pOldPlot->removeUnit(this, bUpdate);

		pOldPlot->changeAdjacentSight(getTeam(), visibilityRange(), false, this, true);

		pOldPlot->area()->changeUnitsPerPlayer(getOwnerINLINE(), -1);
		pOldPlot->area()->changePower(getOwnerINLINE(), -(m_pUnitInfo->getPowerValue()));

		if (AI_getUnitAIType() != NO_UNITAI)
		{
			pOldPlot->area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), -1);
		}

		if (isAnimal())
		{
			pOldPlot->area()->changeAnimalsPerPlayer(getOwnerINLINE(), -1);
		}

		if (pOldPlot->getTeam() != getTeam() && (pOldPlot->getTeam() == NO_TEAM || !GET_TEAM(pOldPlot->getTeam()).isVassal(getTeam())))
		{
			GET_PLAYER(getOwnerINLINE()).changeNumOutsideUnits(-1);
		}

		setLastMoveTurn(GC.getGameINLINE().getTurnSlice());

		pOldCity = pOldPlot->getPlotCity();

		if (pOldCity != NULL)
		{
			if (isMilitaryHappiness())
			{
				pOldCity->changeMilitaryHappinessUnits(-1);
			}
		}

		pWorkingCity = pOldPlot->getWorkingCity();

		if (pWorkingCity != NULL)
		{
			if (canSiege(pWorkingCity->getTeam()))
			{
				pWorkingCity->AI_setAssignWorkDirty(true);
			}
		}

		if (pOldPlot->isWater())
		{
			for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				pLoopPlot = plotDirection(pOldPlot->getX_INLINE(), pOldPlot->getY_INLINE(), ((DirectionTypes)iI));

				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater())
					{
						pWorkingCity = pLoopPlot->getWorkingCity();

						if (pWorkingCity != NULL)
						{
							if (canSiege(pWorkingCity->getTeam()))
							{
								pWorkingCity->AI_setAssignWorkDirty(true);
							}
						}
					}
				}
			}
		}

		if (pOldPlot->isActiveVisible(true))
		{
			pOldPlot->updateMinimapColor();
		}

		if (pOldPlot == gDLL->getInterfaceIFace()->getSelectionPlot())
		{
			gDLL->getInterfaceIFace()->verifyPlotListColumn();

			gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
		}
	}

	if (pNewPlot != NULL)
	{
		m_iX = pNewPlot->getX_INLINE();
		m_iY = pNewPlot->getY_INLINE();
	}
	else
	{
		m_iX = INVALID_PLOT_COORD;
		m_iY = INVALID_PLOT_COORD;
	}

	FAssertMsg(plot() == pNewPlot, "plot is expected to equal pNewPlot");

	if (pNewPlot != NULL)
	{
		pNewCity = pNewPlot->getPlotCity();

		if (pNewCity != NULL)
		{
			if (isEnemy(pNewCity->getTeam()) && !canCoexistWithEnemyUnit(pNewCity->getTeam()))
			{
				GET_TEAM(getTeam()).changeWarWeariness(pNewCity->getTeam(), *pNewPlot, GC.getDefineINT("WW_CAPTURED_CITY"));
				GET_TEAM(getTeam()).AI_changeWarSuccess(pNewCity->getTeam(), GC.getDefineINT("WAR_SUCCESS_CITY_CAPTURING"));

				PlayerTypes eNewOwner = GET_PLAYER(getOwnerINLINE()).pickConqueredCityOwner(*pNewCity);

				if (NO_PLAYER != eNewOwner)
				{
					GET_PLAYER(eNewOwner).acquireCity(pNewCity, true, false, true); // will delete the pointer
					pNewCity = NULL;
				}
			}
		}

		//update facing direction
		if(pOldPlot != NULL)
		{
			DirectionTypes newDirection = estimateDirection(pOldPlot, pNewPlot);
			if(newDirection != NO_DIRECTION)
				m_eFacingDirection = newDirection;
		}

		//update cargo mission animations
		if (isCargo())
		{
			if (eOldActivityType != ACTIVITY_MISSION)
			{
				getGroup()->setActivityType(eOldActivityType);
			}
		}

		setFortifyTurns(0);

		pNewPlot->changeAdjacentSight(getTeam(), visibilityRange(), true, this, true); // needs to be here so that the square is considered visible when we move into it...

		pNewPlot->addUnit(this, bUpdate);

		pNewPlot->area()->changeUnitsPerPlayer(getOwnerINLINE(), 1);
		pNewPlot->area()->changePower(getOwnerINLINE(), m_pUnitInfo->getPowerValue());

		if (AI_getUnitAIType() != NO_UNITAI)
		{
			pNewPlot->area()->changeNumAIUnits(getOwnerINLINE(), AI_getUnitAIType(), 1);
		}

		if (isAnimal())
		{
			pNewPlot->area()->changeAnimalsPerPlayer(getOwnerINLINE(), 1);
		}

		if (pNewPlot->getTeam() != getTeam() && (pNewPlot->getTeam() == NO_TEAM || !GET_TEAM(pNewPlot->getTeam()).isVassal(getTeam())))
		{
			GET_PLAYER(getOwnerINLINE()).changeNumOutsideUnits(1);
		}

		if (shouldLoadOnMove(pNewPlot))
		{
			load();
		}

		for (iI = 0; iI < MAX_CIV_TEAMS; iI++)
		{
			if (GET_TEAM((TeamTypes)iI).isAlive())
			{
				if (!isInvisible(((TeamTypes)iI), false))
				{
					if (pNewPlot->isVisible((TeamTypes)iI, false))
					{
						GET_TEAM((TeamTypes)iI).meet(getTeam(), true);
					}
				}
			}
		}

		pNewCity = pNewPlot->getPlotCity();

		if (pNewCity != NULL)
		{
			if (isMilitaryHappiness())
			{
				pNewCity->changeMilitaryHappinessUnits(1);
			}
		}

		pWorkingCity = pNewPlot->getWorkingCity();

		if (pWorkingCity != NULL)
		{
			if (canSiege(pWorkingCity->getTeam()))
			{
				pWorkingCity->verifyWorkingPlot(pWorkingCity->getCityPlotIndex(pNewPlot));
			}
		}

		if (pNewPlot->isWater())
		{
			for (iI = 0; iI < NUM_DIRECTION_TYPES; iI++)
			{
				pLoopPlot = plotDirection(pNewPlot->getX_INLINE(), pNewPlot->getY_INLINE(), ((DirectionTypes)iI));

				if (pLoopPlot != NULL)
				{
					if (pLoopPlot->isWater())
					{
						pWorkingCity = pLoopPlot->getWorkingCity();

						if (pWorkingCity != NULL)
						{
							if (canSiege(pWorkingCity->getTeam()))
							{
								pWorkingCity->verifyWorkingPlot(pWorkingCity->getCityPlotIndex(pLoopPlot));
							}
						}
					}
				}
			}
		}

		if (pNewPlot->isActiveVisible(true))
		{
			pNewPlot->updateMinimapColor();
		}

		if (GC.IsGraphicsInitialized())
		{
			//override bShow if check plot visible
			if(bCheckPlotVisible && pNewPlot->isVisibleToWatchingHuman())
				bShow = true;

			if (bShow)
			{
				QueueMove(pNewPlot);
			}
			else
			{
				SetPosition(pNewPlot);
			}
		}

		if (pNewPlot == gDLL->getInterfaceIFace()->getSelectionPlot())
		{
			gDLL->getInterfaceIFace()->verifyPlotListColumn();

			gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
		}
	}

	if (pOldPlot != NULL)
	{
		if (hasCargo())
		{
			pUnitNode = pOldPlot->headUnitNode();

			while (pUnitNode != NULL)
			{
				pLoopUnit = ::getUnit(pUnitNode->m_data);
				pUnitNode = pOldPlot->nextUnitNode(pUnitNode);

				if (pLoopUnit->getTransportUnit() == this)
				{
					pLoopUnit->setXY(iX, iY, bGroup, bUpdate);
				}
			}
		}
	}

	FAssert(pOldPlot != pNewPlot);
	GET_PLAYER(getOwnerINLINE()).updateGroupCycle(this);

	setInfoBarDirty(true);

	if (IsSelected())
	{
		if (isFound())
		{
			gDLL->getInterfaceIFace()->setDirty(GlobeLayer_DIRTY_BIT, true);
			gDLL->getEngineIFace()->updateFoundingBorder();
		}

		gDLL->getInterfaceIFace()->setDirty(ColoredPlots_DIRTY_BIT, true);
	}

	//update glow
	gDLL->getEntityIFace()->updateEnemyGlow(getUnitEntity());

	// report event to Python, along with some other key state
	gDLL->getEventReporterIFace()->unitSetXY(pNewPlot, this);
}


bool CvUnit::at(int iX, int iY) const
{
	return((getX_INLINE() == iX) && (getY_INLINE() == iY));
}


bool CvUnit::atPlot(const CvPlot* pPlot) const
{
	return (plot() == pPlot);
}


CvPlot* CvUnit::plot() const
{
	return GC.getMapINLINE().plotSorenINLINE(getX_INLINE(), getY_INLINE());
}


int CvUnit::getArea() const
{
	return plot()->getArea();
}


CvArea* CvUnit::area() const
{
	return plot()->area();
}


bool CvUnit::onMap() const
{
	return (plot() != NULL);
}


int CvUnit::getLastMoveTurn() const
{
	return m_iLastMoveTurn;
}


void CvUnit::setLastMoveTurn(int iNewValue)
{
	m_iLastMoveTurn = iNewValue;
	FAssert(getLastMoveTurn() >= 0);
}


CvPlot* CvUnit::getReconPlot() const
{
	return GC.getMapINLINE().plotSorenINLINE(m_iReconX, m_iReconY);
}


void CvUnit::setReconPlot(CvPlot* pNewValue)
{
	CvPlot* pOldPlot;

	pOldPlot = getReconPlot();

	if (pOldPlot != pNewValue)
	{
		if (pOldPlot != NULL)
		{
			pOldPlot->changeAdjacentSight(getTeam(), GC.getDefineINT("RECON_VISIBILITY_RANGE"), false, this, true);
			pOldPlot->changeReconCount(-1); // changeAdjacentSight() tests for getReconCount()
		}

		if (pNewValue == NULL)
		{
			m_iReconX = INVALID_PLOT_COORD;
			m_iReconY = INVALID_PLOT_COORD;
		}
		else
		{
			m_iReconX = pNewValue->getX_INLINE();
			m_iReconY = pNewValue->getY_INLINE();

			pNewValue->changeReconCount(1); // changeAdjacentSight() tests for getReconCount()
			pNewValue->changeAdjacentSight(getTeam(), GC.getDefineINT("RECON_VISIBILITY_RANGE"), true, this, true);
		}
	}
}


int CvUnit::getGameTurnCreated() const
{
	return m_iGameTurnCreated;
}


void CvUnit::setGameTurnCreated(int iNewValue)
{
	m_iGameTurnCreated = iNewValue;
	FAssert(getGameTurnCreated() >= 0);
}


int CvUnit::getDamage() const
{
	return m_iDamage;
}


void CvUnit::setDamage(int iNewValue, PlayerTypes ePlayer, bool bNotifyEntity)
{
	int iOldValue;

	iOldValue = getDamage();

	m_iDamage = range(iNewValue, 0, maxHitPoints());

	FAssertMsg(currHitPoints() >= 0, "currHitPoints() is expected to be non-negative (invalid Index)");

	if (iOldValue != getDamage())
	{
		if (GC.getGameINLINE().isFinalInitialized() && bNotifyEntity)
		{
			NotifyEntity(MISSION_DAMAGE);
		}

		setInfoBarDirty(true);

		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
		}

		if (plot() == gDLL->getInterfaceIFace()->getSelectionPlot())
		{
			gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
		}
	}

	if (isDead())
	{
		kill(true, ePlayer);
	}
}


void CvUnit::changeDamage(int iChange, PlayerTypes ePlayer)
{
	setDamage((getDamage() + iChange), ePlayer);
}


int CvUnit::getMoves() const
{
	return m_iMoves;
}


void CvUnit::setMoves(int iNewValue)
{
	CvPlot* pPlot;

	if (getMoves() != iNewValue)
	{
		pPlot = plot();

		m_iMoves = iNewValue;

		FAssert(getMoves() >= 0);

		if (getTeam() == GC.getGameINLINE().getActiveTeam())
		{
			if (pPlot != NULL)
			{
				pPlot->setFlagDirty(true);
			}
		}

		if (IsSelected())
		{
			gDLL->getFAStarIFace()->ForceReset(&GC.getInterfacePathFinder());

			gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
		}

		if (pPlot == gDLL->getInterfaceIFace()->getSelectionPlot())
		{
			gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
		}
	}
}


void CvUnit::changeMoves(int iChange)
{
	setMoves(getMoves() + iChange);
}


void CvUnit::finishMoves()
{
	setMoves(maxMoves());
}


int CvUnit::getExperience() const
{
	return m_iExperience;
}


void CvUnit::setExperience(int iNewValue, int iMax)
{
	if ((getExperience() != iNewValue) && (getExperience() < ((iMax == -1) ? MAX_INT : iMax)))
	{
		m_iExperience = std::min(((iMax == -1) ? MAX_INT : iMax), iNewValue);
		FAssert(getExperience() >= 0);

		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
		}
	}
}


void CvUnit::changeExperience(int iChange, int iMax, bool bFromCombat, bool bInBorders, bool bUpdateGlobal)
{
	int iUnitExperience = iChange;

	if (bFromCombat)
	{
		CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());

		int iCombatExperienceMod = 100 + kPlayer.getGreatGeneralRateModifier();

		if (bInBorders)
		{
			iCombatExperienceMod += kPlayer.getDomesticGreatGeneralRateModifier() + kPlayer.getExpInBorderModifier();
			iUnitExperience += (iChange * kPlayer.getExpInBorderModifier()) / 100;
		}

		if (bUpdateGlobal)
		{
			kPlayer.changeCombatExperience((iChange * iCombatExperienceMod) / 100);
		}

		if (getExperiencePercent() != 0)
		{
			iUnitExperience *= std::max(0, 100 + getExperiencePercent());
			iUnitExperience /= 100;
		}
	}

	setExperience((getExperience() + iUnitExperience), iMax);
}


int CvUnit::getLevel() const
{
	return m_iLevel;
}


void CvUnit::setLevel(int iNewValue)
{
	if (getLevel() != iNewValue)
	{
		m_iLevel = iNewValue;
		FAssert(getLevel() >= 0);

		if (getLevel() > GET_PLAYER(getOwnerINLINE()).getHighestUnitLevel())
		{
			GET_PLAYER(getOwnerINLINE()).setHighestUnitLevel(getLevel());
		}

		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
		}
	}
}


void CvUnit::changeLevel(int iChange)
{
	setLevel(getLevel() + iChange);
}


int CvUnit::getCargo() const
{
	return m_iCargo;
}


void CvUnit::changeCargo(int iChange)
{
	m_iCargo = (m_iCargo + iChange);
	FAssert(getCargo() >= 0);
}


CvPlot* CvUnit::getAttackPlot() const
{
	return GC.getMapINLINE().plotSorenINLINE(m_iAttackPlotX, m_iAttackPlotY);
}


void CvUnit::setAttackPlot(const CvPlot* pNewValue, bool bAirCombat)
{
	if (getAttackPlot() != pNewValue)
	{
		if (pNewValue != NULL)
		{
			m_iAttackPlotX = pNewValue->getX_INLINE();
			m_iAttackPlotY = pNewValue->getY_INLINE();
		}
		else
		{
			m_iAttackPlotX = INVALID_PLOT_COORD;
			m_iAttackPlotY = INVALID_PLOT_COORD;
		}
	}

	m_bAirCombat = bAirCombat;
}

bool CvUnit::isAirCombat() const
{
	return m_bAirCombat;
}


int CvUnit::getCombatTimer() const
{
	return m_iCombatTimer;
}


void CvUnit::setCombatTimer(int iNewValue)
{
	m_iCombatTimer = iNewValue;
	FAssert(getCombatTimer() >= 0);
}


void CvUnit::changeCombatTimer(int iChange)
{
	setCombatTimer(getCombatTimer() + iChange);
}


int CvUnit::getCombatFirstStrikes() const
{
	return m_iCombatFirstStrikes;
}


void CvUnit::setCombatFirstStrikes(int iNewValue)
{
	m_iCombatFirstStrikes = iNewValue;
	FAssert(getCombatFirstStrikes() >= 0);
}


void CvUnit::changeCombatFirstStrikes(int iChange)
{
	setCombatFirstStrikes(getCombatFirstStrikes() + iChange);
}


int CvUnit::getCombatDamage() const
{
	return m_iCombatDamage;
}


void CvUnit::setCombatDamage(int iNewValue)
{
	m_iCombatDamage = iNewValue;
	FAssert(getCombatDamage() >= 0);
}


int CvUnit::getFortifyTurns() const
{
	return m_iFortifyTurns;
}


void CvUnit::setFortifyTurns(int iNewValue)
{
	iNewValue = range(iNewValue, 0, GC.getDefineINT("MAX_FORTIFY_TURNS"));

	if (iNewValue != getFortifyTurns())
	{
		m_iFortifyTurns = iNewValue;
		setInfoBarDirty(true);
	}
}


void CvUnit::changeFortifyTurns(int iChange)
{
	setFortifyTurns(getFortifyTurns() + iChange);
}


int CvUnit::getBlitzCount() const
{
	return m_iBlitzCount;
}


bool CvUnit::isBlitz() const
{
	return (getBlitzCount() > 0);
}


void CvUnit::changeBlitzCount(int iChange)
{
	m_iBlitzCount = (m_iBlitzCount + iChange);
	FAssert(getBlitzCount() >= 0);
}


int CvUnit::getAmphibCount() const
{
	return m_iAmphibCount;
}


bool CvUnit::isAmphib() const
{
	return (getAmphibCount() > 0);
}


void CvUnit::changeAmphibCount(int iChange)
{
	m_iAmphibCount = (m_iAmphibCount + iChange);
	FAssert(getAmphibCount() >= 0);
}


int CvUnit::getRiverCount() const
{
	return m_iRiverCount;
}


bool CvUnit::isRiver() const
{
	return (getRiverCount() > 0);
}


void CvUnit::changeRiverCount(int iChange)
{
	m_iRiverCount = (m_iRiverCount + iChange);
	FAssert(getRiverCount() >= 0);
}


/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**						Loads & Tracks all Promotion Information for the Unit					**/
/*************************************************************************************************/
int CvUnit::getTerritorialCount() const
{
	return m_iTerritorialCount;
}
bool CvUnit::isTerritorial() const
{
	return (getTerritorialCount() > 0);
}
void CvUnit::changeTerritorialCount(int iChange)
{
	m_iTerritorialCount = (m_iTerritorialCount + iChange);
	FAssert(getTerritorialCount() >= 0);
}

int CvUnit::getRivalTerritoryExploreCount() const
{
	return m_iRivalTerritoryExploreCount;
}
bool CvUnit::isRivalTerritoryExplore() const
{
	return (getRivalTerritoryExploreCount() > 0);
}
void CvUnit::changeRivalTerritoryExploreCount(int iChange)
{
	m_iRivalTerritoryExploreCount = (m_iRivalTerritoryExploreCount + iChange);
	FAssert(getRivalTerritoryExploreCount() >= 0);
}

int CvUnit::getRivalTerritoryBlockCount() const
{
	return m_iRivalTerritoryBlockCount;
}
bool CvUnit::isRivalTerritoryBlock() const
{
	return (getRivalTerritoryBlockCount() > 0);
}
void CvUnit::changeRivalTerritoryBlockCount(int iChange)
{
	m_iRivalTerritoryBlockCount = (m_iRivalTerritoryBlockCount + iChange);
	FAssert(getRivalTerritoryBlockCount() >= 0);
}

int CvUnit::getPillageOnMoveCount() const
{
	return m_iPillageOnMoveCount;
}
bool CvUnit::isPillageOnMove() const
{
	return (getPillageOnMoveCount() > 0);
}
void CvUnit::changePillageOnMoveCount(int iChange)
{
	m_iPillageOnMoveCount = (m_iPillageOnMoveCount + iChange);
	FAssert(getPillageOnMoveCount() >= 0);
}

int CvUnit::getSelfPillageCount() const
{
	return m_iSelfPillageCount;
}
bool CvUnit::isSelfPillage() const
{
	return (getSelfPillageCount() > 0);
}
void CvUnit::changeSelfPillageCount(int iChange)
{
	m_iSelfPillageCount = (m_iSelfPillageCount + iChange);
	FAssert(getSelfPillageCount() >= 0);
}

int CvUnit::getGetCasterXPCount() const
{
	return m_iGetCasterXPCount;
}
bool CvUnit::isGetCasterXP() const
{
	return (getGetCasterXPCount() > 0);
}
void CvUnit::changeGetCasterXPCount(int iChange)
{
	m_iGetCasterXPCount = (m_iGetCasterXPCount + iChange);
	FAssert(getGetCasterXPCount() >= 0);
}

int CvUnit::getNonWarWearinessCount() const
{
	return m_iNonWarWearinessCount;
}
bool CvUnit::isNonWarWeariness() const
{
	return (getNonWarWearinessCount() > 0);
}
void CvUnit::changeNonWarWearinessCount(int iChange)
{
	m_iNonWarWearinessCount = (m_iNonWarWearinessCount + iChange);
	FAssert(getNonWarWearinessCount() >= 0);
}

int CvUnit::getNoMapRevealCount() const
{
	return m_iNoMapRevealCount;
}
bool CvUnit::isNoMapReveal() const
{
	return (getNoMapRevealCount() > 0);
}
void CvUnit::changeNoMapRevealCount(int iChange)
{
	m_iNoMapRevealCount = (m_iNoMapRevealCount + iChange);
	FAssert(getNoMapRevealCount() >= 0);
}

int CvUnit::getCannotCaptureCount() const
{
	return m_iCannotCaptureCount;
}
bool CvUnit::isCannotCapture() const
{
	return (getCannotCaptureCount() > 0);
}
void CvUnit::changeCannotCaptureCount(int iChange)
{
	m_iCannotCaptureCount = (m_iCannotCaptureCount + iChange);
	FAssert(getCannotCaptureCount() >= 0);
}

int CvUnit::getCityHappyCount() const
{
	return m_iCityHappyCount;
}
bool CvUnit::isCityHappy() const
{
	return (getCityHappyCount() > 0);
}
void CvUnit::changeCityHappyCount(int iChange)
{
	m_iCityHappyCount = (m_iCityHappyCount + iChange);
	FAssert(getCityHappyCount() >= 0);
}

int CvUnit::getCityNoHappyCount() const
{
	return m_iCityNoHappyCount;
}
bool CvUnit::isCityNoHappy() const
{
	return (getCityNoHappyCount() > 0);
}
void CvUnit::changeCityNoHappyCount(int iChange)
{
	m_iCityNoHappyCount = (m_iCityNoHappyCount + iChange);
	FAssert(getCityNoHappyCount() >= 0);
}

int CvUnit::getNoSupportCount() const
{
	return m_iNoSupportCount;
}
bool CvUnit::isNoSupport() const
{
	return (getNoSupportCount() > 0);
}
void CvUnit::changeNoSupportCount(int iChange)
{
	m_iNoSupportCount = (m_iNoSupportCount + iChange);
	FAssert(getNoSupportCount() >= 0);
}

int CvUnit::getCanPillageCount() const
{
	return m_iCanPillageCount;
}
bool CvUnit::isCanPillage() const
{
	return (getCanPillageCount() > 0);
}
void CvUnit::changeCanPillageCount(int iChange)
{
	m_iCanPillageCount = (m_iCanPillageCount + iChange);
	FAssert(getCanPillageCount() >= 0);
}

int CvUnit::getCannotPillageCount() const
{
	return m_iCannotPillageCount;
}
bool CvUnit::isCannotPillage() const
{
	return (getCannotPillageCount() > 0);
}
void CvUnit::changeCannotPillageCount(int iChange)
{
	m_iCannotPillageCount = (m_iCannotPillageCount + iChange);
	FAssert(getCannotPillageCount() >= 0);
}

int CvUnit::getCitySpyCount() const
{
	return m_iCitySpyCount;
}
bool CvUnit::isCitySpy() const
{
	return (getCitySpyCount() > 0);
}
void CvUnit::changeCitySpyCount(int iChange)
{
	m_iCitySpyCount = (m_iCitySpyCount + iChange);
	FAssert(getCitySpyCount() >= 0);
}

int CvUnit::getStartGoldenAgeCount() const
{
	return m_iStartGoldenAgeCount;
}
bool CvUnit::isStartGoldenAge() const
{
	return (getStartGoldenAgeCount() > 0);
}
void CvUnit::changeStartGoldenAgeCount(int iChange)
{
	m_iStartGoldenAgeCount = (m_iStartGoldenAgeCount + iChange);
	FAssert(getStartGoldenAgeCount() >= 0);
}

int CvUnit::getNoDefenseBonusCount() const
{
	return m_iNoDefenseBonusCount;
}
bool CvUnit::isNoDefenseBonus() const
{
	return (getNoDefenseBonusCount() > 0);
}
void CvUnit::changeNoDefenseBonusCount(int iChange)
{
	m_iNoDefenseBonusCount = (m_iNoDefenseBonusCount + iChange);
	FAssert(getNoDefenseBonusCount() >= 0);
}

int CvUnit::getMoveImpassableCount() const
{
	return m_iMoveImpassableCount;
}
bool CvUnit::isMoveImpassable() const
{
	return (getMoveImpassableCount() > 0);
}
void CvUnit::changeMoveImpassableCount(int iChange)
{
	m_iMoveImpassableCount = (m_iMoveImpassableCount + iChange);
	FAssert(getMoveImpassableCount() >= 0);
}

int CvUnit::getFlatMoveCostCount() const
{
	return m_iFlatMoveCostCount;
}
bool CvUnit::isFlatMoveCost() const
{
	return (getFlatMoveCostCount() > 0);
}
void CvUnit::changeFlatMoveCostCount(int iChange)
{
	m_iFlatMoveCostCount = (m_iFlatMoveCostCount + iChange);
	FAssert(getFlatMoveCostCount() >= 0);
}

int CvUnit::getIgnoreTerrainCostsCount() const
{
	return m_iIgnoreTerrainCostsCount;
}
bool CvUnit::isIgnoreTerrainCosts() const
{
	return (getIgnoreTerrainCostsCount() > 0);
}
void CvUnit::changeIgnoreTerrainCostsCount(int iChange)
{
	m_iIgnoreTerrainCostsCount = (m_iIgnoreTerrainCostsCount + iChange);
	FAssert(getIgnoreTerrainCostsCount() >= 0);
}

int CvUnit::getAttackNoWarCount() const
{
	return m_iAttackNoWarCount;
}
bool CvUnit::isAttackNoWar() const
{
	return (getAttackNoWarCount() > 0);
}
void CvUnit::changeAttackNoWarCount(int iChange)
{
	m_iAttackNoWarCount = (m_iAttackNoWarCount + iChange);
	FAssert(getAttackNoWarCount() >= 0);
}

int CvUnit::getAllowAttacksCount() const
{
	return m_iAllowAttacksCount;
}
bool CvUnit::isAllowAttacks() const
{
	return (getAllowAttacksCount() > 0);
}
void CvUnit::changeAllowAttacksCount(int iChange)
{
	m_iAllowAttacksCount = (m_iAllowAttacksCount + iChange);
	FAssert(getAllowAttacksCount() >= 0);
}

int CvUnit::getFirstStrikeVulnerableCount() const
{
	return m_iFirstStrikeVulnerableCount;
}
bool CvUnit::isFirstStrikeVulnerable() const
{
	return (getFirstStrikeVulnerableCount() > 0);
}
void CvUnit::changeFirstStrikeVulnerableCount(int iChange)
{
	m_iFirstStrikeVulnerableCount = (m_iFirstStrikeVulnerableCount + iChange);
	FAssert(getFirstStrikeVulnerableCount() >= 0);
}

int CvUnit::getAllowDefenseBonusesCount() const
{
	return m_iAllowDefenseBonusesCount;
}
bool CvUnit::isAllowDefenseBonuses() const
{
	return (getAllowDefenseBonusesCount() > 0);
}
void CvUnit::changeAllowDefenseBonusesCount(int iChange)
{
	m_iAllowDefenseBonusesCount = (m_iAllowDefenseBonusesCount + iChange);
	FAssert(getAllowDefenseBonusesCount() >= 0);
}

int CvUnit::getNonAbandonCount() const
{
	return m_iNonAbandonCount;
}
bool CvUnit::isNonAbandon() const
{
	return (getNonAbandonCount() > 0);
}
void CvUnit::changeNonAbandonCount(int iChange)
{
	m_iNonAbandonCount = (m_iNonAbandonCount + iChange);
	FAssert(getNonAbandonCount() >= 0);
}

int CvUnit::getIndependantCount() const
{
	return m_iIndependantCount;
}
bool CvUnit::isIndependant() const
{
	return (getIndependantCount() > 0);
}
void CvUnit::changeIndependantCount(int iChange)
{
	m_iIndependantCount = (m_iIndependantCount + iChange);
	FAssert(getIndependantCount() >= 0);
}


int CvUnit::getWorkRateChange() const
{
	return m_iWorkRateChange;
}
void CvUnit::setWorkRateChange(int iNewValue)
{
	m_iWorkRateChange = iNewValue;
}
void CvUnit::changeWorkRateChange(int iChange)
{
	setWorkRateChange(getWorkRateChange() + iChange);
}

int CvUnit::getCombatConversionChance() const
{
	return m_iCombatConversionChance;
}
void CvUnit::setCombatConversionChance(int iNewValue)
{
	m_iCombatConversionChance = iNewValue;
}
void CvUnit::changeCombatConversionChance(int iChange)
{
	setCombatConversionChance(getCombatConversionChance() + iChange);
}

int CvUnit::getCombatUnitGenerationChance() const
{
	return m_iCombatUnitGenerationChance;
}
void CvUnit::setCombatUnitGenerationChance(int iNewValue)
{
	m_iCombatUnitGenerationChance = iNewValue;
}
void CvUnit::changeCombatUnitGenerationChance(int iChange)
{
	setCombatUnitGenerationChance(getCombatUnitGenerationChance() + iChange);
}

int CvUnit::getSlaveGenerationChance() const
{
	return m_iSlaveGenerationChance;
}
void CvUnit::setSlaveGenerationChance(int iNewValue)
{
	m_iSlaveGenerationChance = iNewValue;
}
void CvUnit::changeSlaveGenerationChance(int iChange)
{
	setSlaveGenerationChance(getSlaveGenerationChance() + iChange);
}

int CvUnit::getGiftableXP() const
{
	return m_iGiftableXP;
}
void CvUnit::setGiftableXP(int iNewValue)
{
	m_iGiftableXP = iNewValue;
}
void CvUnit::changeGiftableXP(int iChange)
{
	setGiftableXP(getGiftableXP() + iChange);
}

int CvUnit::getCombatExtraDuration() const
{
	return m_iCombatExtraDuration;
}
void CvUnit::setCombatExtraDuration(int iNewValue)
{
	m_iCombatExtraDuration = iNewValue;
}
void CvUnit::changeCombatExtraDuration(int iChange)
{
	setCombatExtraDuration(getCombatExtraDuration() + iChange);
}

int CvUnit::getDurationPerTurn() const
{
	return m_iDurationPerTurn;
}
void CvUnit::setDurationPerTurn(int iNewValue)
{
	m_iDurationPerTurn = iNewValue;
}
void CvUnit::changeDurationPerTurn(int iChange)
{
	setDurationPerTurn(getDurationPerTurn() + iChange);
}

void CvUnit::changeDurationAlter(int iChange)
{
/*************************************************************************************************/
/**	Ephemereal						05/19/08										Xienwolf	**/
/**						Only Temporary Units are affected by this field							**/
/**				Gaining/Losing this Promotion Field cannot cause a Unit to Expire				**/
/*************************************************************************************************/
	if (getDuration() != 0)
	{
        changeDuration(iChange);

        if (getDuration() <= 0)
        {
            setDuration(1);
        }
	}
/*************************************************************************************************/
/**	Ephemereal  								END												**/
/*************************************************************************************************/
}

int CvUnit::getChangeDuration() const
{
	return m_iChangeDuration;
}
void CvUnit::setChangeDuration(int iNewValue)
{
	m_iChangeDuration = iNewValue;
}
void CvUnit::changeChangeDuration(int iChange)
{
    setChangeDuration(getChangeDuration() + iChange);
/*************************************************************************************************/
/**	Durable							05/19/08										Xienwolf	**/
/**																								**/
/**			Gaining/Losing this Promotion Field cannot cause a Unit to immediately Expire		**/
/*************************************************************************************************/
	if (getDuration() == 0)
	{
	    m_bNonTemporary = true;
    }

    changeDuration(iChange);

    if (getDuration() <= 0)
    {
        if (m_bNonTemporary)
        {
            setDuration(0);
        }
        else
        {
            setDuration(1);
        }
    }
/*************************************************************************************************/
/**	Durable										END												**/
/*************************************************************************************************/
}

int CvUnit::getExtraSupport() const
{
	return m_iExtraSupport;
}
void CvUnit::setExtraSupport(int iNewValue)
{
	m_iExtraSupport = iNewValue;
}
void CvUnit::changeExtraSupport(int iChange)
{
	setExtraSupport(getExtraSupport() + iChange);
}

int CvUnit::getChanceMiscast() const
{
	return m_iChanceMiscast;
}
void CvUnit::setChanceMiscast(int iNewValue)
{
	m_iChanceMiscast = iNewValue;
}
void CvUnit::changeChanceMiscast(int iChange)
{
	setChanceMiscast(getChanceMiscast() + iChange);
}

int CvUnit::getCombatDmgCap() const
{
	return m_iCombatDmgCap;
}
void CvUnit::setCombatDmgCap(int iNewValue)
{
	m_iCombatDmgCap = iNewValue;
}
void CvUnit::changeCombatDmgCap(int iChange)
{
	setCombatDmgCap(getCombatDmgCap() + iChange);
}

int CvUnit::getCombatDmgCapBoost() const
{
	return m_iCombatDmgCapBoost;
}
void CvUnit::setCombatDmgCapBoost(int iNewValue)
{
	m_iCombatDmgCapBoost = iNewValue;
}
void CvUnit::changeCombatDmgCapBoost(int iChange)
{
	setCombatDmgCapBoost(getCombatDmgCapBoost() + iChange);
}

int CvUnit::getCollateralLimitCap() const
{
	return m_iCollateralLimitCap;
}
void CvUnit::setCollateralLimitCap(int iNewValue)
{
	m_iCollateralLimitCap = iNewValue;
}
void CvUnit::changeCollateralLimitCap(int iChange)
{
	setCollateralLimitCap(getCollateralLimitCap() + iChange);
}

int CvUnit::getCollateralLimitBoost() const
{
	return m_iCollateralLimitBoost;
}
void CvUnit::setCollateralLimitBoost(int iNewValue)
{
	m_iCollateralLimitBoost = iNewValue;
}
void CvUnit::changeCollateralLimitBoost(int iChange)
{
	setCollateralLimitBoost(getCollateralLimitBoost() + iChange);
}

int CvUnit::getCollateralTargetsLimit() const
{
	return m_iCollateralTargetsLimit;
}
void CvUnit::setCollateralTargetsLimit(int iNewValue)
{
	m_iCollateralTargetsLimit = iNewValue;
}
void CvUnit::changeCollateralTargetsLimit(int iChange)
{
	setCollateralTargetsLimit(getCollateralTargetsLimit() + iChange);
}

int CvUnit::getCollateralExtraTargets() const
{
	return m_iCollateralExtraTargets;
}
void CvUnit::setCollateralExtraTargets(int iNewValue)
{
	m_iCollateralExtraTargets = iNewValue;
}
void CvUnit::changeCollateralExtraTargets(int iChange)
{
	setCollateralExtraTargets(getCollateralExtraTargets() + iChange);
}

int CvUnit::getHammerSacrifice() const
{
	return m_iHammerSacrifice;
}
void CvUnit::setHammerSacrifice(int iNewValue)
{
	m_iHammerSacrifice = iNewValue;
}
void CvUnit::changeHammerSacrifice(int iChange)
{
	setHammerSacrifice(getHammerSacrifice() + iChange);
}

int CvUnit::getExtraHammerPerPop() const
{
	return m_iExtraHammerPerPop;
}
void CvUnit::setExtraHammerPerPop(int iNewValue)
{
	m_iExtraHammerPerPop = iNewValue;
}
void CvUnit::changeExtraHammerPerPop(int iChange)
{
	setExtraHammerPerPop(getExtraHammerPerPop() + iChange);
}

int CvUnit::getFoodSacrifice() const
{
	return m_iFoodSacrifice;
}
void CvUnit::setFoodSacrifice(int iNewValue)
{
	m_iFoodSacrifice = iNewValue;
}
void CvUnit::changeFoodSacrifice(int iChange)
{
	setFoodSacrifice(getFoodSacrifice() + iChange);
}

int CvUnit::getPopulationAdd() const
{
	return m_iPopulationAdd;
}
void CvUnit::setPopulationAdd(int iNewValue)
{
	m_iPopulationAdd = iNewValue;
}
void CvUnit::changePopulationAdd(int iChange)
{
	setPopulationAdd(getPopulationAdd() + iChange);
}

int CvUnit::getBeakerSacrifice() const
{
	return m_iBeakerSacrifice;
}
void CvUnit::setBeakerSacrifice(int iNewValue)
{
	m_iBeakerSacrifice = iNewValue;
}
void CvUnit::changeBeakerSacrifice(int iChange)
{
	setBeakerSacrifice(getBeakerSacrifice() + iChange);
}

int CvUnit::getExtraBeakerPerPop() const
{
	return m_iExtraBeakerPerPop;
}
void CvUnit::setExtraBeakerPerPop(int iNewValue)
{
	m_iExtraBeakerPerPop = iNewValue;
}
void CvUnit::changeExtraBeakerPerPop(int iChange)
{
	setExtraBeakerPerPop(getExtraBeakerPerPop() + iChange);
}

int CvUnit::getGoldSacrifice() const
{
	return m_iGoldSacrifice;
}
void CvUnit::setGoldSacrifice(int iNewValue)
{
	m_iGoldSacrifice = iNewValue;
}
void CvUnit::changeGoldSacrifice(int iChange)
{
	setGoldSacrifice(getGoldSacrifice() + iChange);
}

int CvUnit::getExtraGoldPerPop() const
{
	return m_iExtraGoldPerPop;
}
void CvUnit::setExtraGoldPerPop(int iNewValue)
{
	m_iExtraGoldPerPop = iNewValue;
}
void CvUnit::changeExtraGoldPerPop(int iChange)
{
	setExtraGoldPerPop(getExtraGoldPerPop() + iChange);
}

int CvUnit::getCultureSacrifice() const
{
	return m_iCultureSacrifice;
}
void CvUnit::setCultureSacrifice(int iNewValue)
{
	m_iCultureSacrifice = iNewValue;
}
void CvUnit::changeCultureSacrifice(int iChange)
{
	setCultureSacrifice(getCultureSacrifice() + iChange);
}

int CvUnit::getExtraCulturePerPop() const
{
	return m_iExtraCulturePerPop;
}
void CvUnit::setExtraCulturePerPop(int iNewValue)
{
	m_iExtraCulturePerPop = iNewValue;
}
void CvUnit::changeExtraCulturePerPop(int iChange)
{
	setExtraCulturePerPop(getExtraCulturePerPop() + iChange);
}


int CvUnit::getYieldFromWin(int iI) const
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_YIELD_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_piYieldFromWin[iI];
}
void CvUnit::changeYieldFromWin(int iI, int iChange)
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_YIELD_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_piYieldFromWin[iI] = std::max(0, m_piYieldFromWin[iI] + iChange);
	}
}

int CvUnit::getYieldForLoss(int iI) const
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_YIELD_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_piYieldForLoss[iI];
}
void CvUnit::changeYieldForLoss(int iI, int iChange)
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_YIELD_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_piYieldForLoss[iI] = std::max(0, m_piYieldForLoss[iI] + iChange);
	}
}

int CvUnit::getCommerceFromWin(int iI) const
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_COMMERCE_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_piCommerceFromWin[iI];
}
void CvUnit::changeCommerceFromWin(int iI, int iChange)
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_COMMERCE_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_piCommerceFromWin[iI] = std::max(0, m_piCommerceFromWin[iI] + iChange);
	}
}

int CvUnit::getCommerceForLoss(int iI) const
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_COMMERCE_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_piCommerceForLoss[iI];
}
void CvUnit::changeCommerceForLoss(int iI, int iChange)
{
	FAssertMsg(iI >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(iI < NUM_COMMERCE_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_piCommerceForLoss[iI] = std::max(0, m_piCommerceForLoss[iI] + iChange);
	}
}
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
int CvUnit::getEnemyRouteCount() const
{
	return m_iEnemyRouteCount;
}


bool CvUnit::isEnemyRoute() const
{
	return (getEnemyRouteCount() > 0);
}


void CvUnit::changeEnemyRouteCount(int iChange)
{
	m_iEnemyRouteCount = (m_iEnemyRouteCount + iChange);
	FAssert(getEnemyRouteCount() >= 0);
}


int CvUnit::getAlwaysHealCount() const
{
	return m_iAlwaysHealCount;
}


bool CvUnit::isAlwaysHeal() const
{
	return (getAlwaysHealCount() > 0);
}


void CvUnit::changeAlwaysHealCount(int iChange)
{
	m_iAlwaysHealCount = (m_iAlwaysHealCount + iChange);
	FAssert(getAlwaysHealCount() >= 0);
}


int CvUnit::getHillsDoubleMoveCount() const
{
	return m_iHillsDoubleMoveCount;
}


bool CvUnit::isHillsDoubleMove() const
{
	return (getHillsDoubleMoveCount() > 0);
}


void CvUnit::changeHillsDoubleMoveCount(int iChange)
{
	m_iHillsDoubleMoveCount = (m_iHillsDoubleMoveCount + iChange);
	FAssert(getHillsDoubleMoveCount() >= 0);
}


int CvUnit::getImmuneToFirstStrikesCount() const
{
	return m_iImmuneToFirstStrikesCount;
}


void CvUnit::changeImmuneToFirstStrikesCount(int iChange)
{
	m_iImmuneToFirstStrikesCount = (m_iImmuneToFirstStrikesCount + iChange);
	FAssert(getImmuneToFirstStrikesCount() >= 0);
}


int CvUnit::getExtraVisibilityRange() const
{
	return m_iExtraVisibilityRange;
}


void CvUnit::changeExtraVisibilityRange(int iChange)
{
	if (iChange != 0)
	{
		plot()->changeAdjacentSight(getTeam(), visibilityRange(), false, this, true);

		m_iExtraVisibilityRange = (m_iExtraVisibilityRange + iChange);
		FAssert(getExtraVisibilityRange() >= 0);

		plot()->changeAdjacentSight(getTeam(), visibilityRange(), true, this, true);
	}
}


int CvUnit::getExtraMoves() const
{
	return m_iExtraMoves;
}


void CvUnit::changeExtraMoves(int iChange)
{
	m_iExtraMoves += iChange;
	FAssert(getExtraMoves() >= 0);
}


int CvUnit::getExtraMoveDiscount() const
{
	return m_iExtraMoveDiscount;
}


void CvUnit::changeExtraMoveDiscount(int iChange)
{
	m_iExtraMoveDiscount = (m_iExtraMoveDiscount + iChange);
	FAssert(getExtraMoveDiscount() >= 0);
}


int CvUnit::getExtraAirRange() const
{
	return m_iExtraAirRange;
}


void CvUnit::changeExtraAirRange(int iChange)
{
	m_iExtraAirRange += iChange;
}


int CvUnit::getExtraIntercept() const
{
	return m_iExtraIntercept;
}


void CvUnit::changeExtraIntercept(int iChange)
{
	m_iExtraIntercept += iChange;
}


int CvUnit::getExtraEvasion() const
{
	return m_iExtraEvasion;
}


void CvUnit::changeExtraEvasion(int iChange)
{
	m_iExtraEvasion += iChange;
}


int CvUnit::getExtraFirstStrikes() const
{
	return m_iExtraFirstStrikes;
}


void CvUnit::changeExtraFirstStrikes(int iChange)
{
	m_iExtraFirstStrikes = (m_iExtraFirstStrikes + iChange);
	FAssert(getExtraFirstStrikes() >= 0);
}


int CvUnit::getExtraChanceFirstStrikes() const
{
	return m_iExtraChanceFirstStrikes;
}


void CvUnit::changeExtraChanceFirstStrikes(int iChange)
{
	m_iExtraChanceFirstStrikes = (m_iExtraChanceFirstStrikes + iChange);
	FAssert(getExtraChanceFirstStrikes() >= 0);
}


int CvUnit::getExtraWithdrawal() const
{
	return m_iExtraWithdrawal;
}


void CvUnit::changeExtraWithdrawal(int iChange)
{
	m_iExtraWithdrawal = (m_iExtraWithdrawal + iChange);
	FAssert(getExtraWithdrawal() >= 0);
}


int CvUnit::getExtraCollateralDamage() const
{
	return m_iExtraCollateralDamage;
}


void CvUnit::changeExtraCollateralDamage(int iChange)
{
	m_iExtraCollateralDamage = (m_iExtraCollateralDamage + iChange);
	FAssert(getExtraCollateralDamage() >= 0);
}


int CvUnit::getExtraBombardRate() const
{
	return m_iExtraBombardRate;
}


void CvUnit::changeExtraBombardRate(int iChange)
{
	m_iExtraBombardRate = (m_iExtraBombardRate + iChange);
	FAssert(getExtraBombardRate() >= 0);
}


int CvUnit::getExtraEnemyHeal() const
{
	return m_iExtraEnemyHeal;
}


void CvUnit::changeExtraEnemyHeal(int iChange)
{
	m_iExtraEnemyHeal = (m_iExtraEnemyHeal + iChange);
	FAssert(getExtraEnemyHeal() >= 0);
}


int CvUnit::getExtraNeutralHeal() const
{
	return m_iExtraNeutralHeal;
}


void CvUnit::changeExtraNeutralHeal(int iChange)
{
	m_iExtraNeutralHeal = (m_iExtraNeutralHeal + iChange);
	FAssert(getExtraNeutralHeal() >= 0);
}


int CvUnit::getExtraFriendlyHeal() const
{
	return m_iExtraFriendlyHeal;
}


void CvUnit::changeExtraFriendlyHeal(int iChange)
{
	m_iExtraFriendlyHeal = (m_iExtraFriendlyHeal + iChange);
	FAssert(getExtraFriendlyHeal() >= 0);
}


int CvUnit::getSameTileHeal() const
{
	return m_iSameTileHeal;
}


void CvUnit::changeSameTileHeal(int iChange)
{
	m_iSameTileHeal = (m_iSameTileHeal + iChange);
	FAssert(getSameTileHeal() >= 0);
}


int CvUnit::getAdjacentTileHeal() const
{
	return m_iAdjacentTileHeal;
}


void CvUnit::changeAdjacentTileHeal(int iChange)
{
	m_iAdjacentTileHeal = (m_iAdjacentTileHeal + iChange);
	FAssert(getAdjacentTileHeal() >= 0);
}


int CvUnit::getExtraCombatPercent() const
{

//FfH: Modified by Kael 10/26/2007
//	return m_iExtraCombatPercent;
	int i = m_iExtraCombatPercent;
    if (plot()->getOwnerINLINE() == getOwnerINLINE())
    {
        i += getCombatPercentInBorders();
    }
	return i;
//FfH: End Modify

}


void CvUnit::changeExtraCombatPercent(int iChange)
{
	if (iChange != 0)
	{
		m_iExtraCombatPercent = (m_iExtraCombatPercent + iChange);

		setInfoBarDirty(true);
	}
}


int CvUnit::getExtraCityAttackPercent() const
{
	return m_iExtraCityAttackPercent;
}


void CvUnit::changeExtraCityAttackPercent(int iChange)
{
	if (iChange != 0)
	{
		m_iExtraCityAttackPercent = (m_iExtraCityAttackPercent + iChange);

		setInfoBarDirty(true);
	}
}


int CvUnit::getExtraCityDefensePercent() const
{
	return m_iExtraCityDefensePercent;
}


void CvUnit::changeExtraCityDefensePercent(int iChange)
{
	if (iChange != 0)
	{
		m_iExtraCityDefensePercent = (m_iExtraCityDefensePercent + iChange);

		setInfoBarDirty(true);
	}
}


int CvUnit::getExtraHillsAttackPercent() const
{
	return m_iExtraHillsAttackPercent;
}


void CvUnit::changeExtraHillsAttackPercent(int iChange)
{
	if (iChange != 0)
	{
		m_iExtraHillsAttackPercent = (m_iExtraHillsAttackPercent + iChange);

		setInfoBarDirty(true);
	}
}


int CvUnit::getExtraHillsDefensePercent() const
{
	return m_iExtraHillsDefensePercent;
}


void CvUnit::changeExtraHillsDefensePercent(int iChange)
{
	if (iChange != 0)
	{
		m_iExtraHillsDefensePercent = (m_iExtraHillsDefensePercent + iChange);

		setInfoBarDirty(true);
	}
}

int CvUnit::getRevoltProtection() const
{
	return m_iRevoltProtection;
}

void CvUnit::changeRevoltProtection(int iChange)
{
	if (iChange != 0)
	{
		m_iRevoltProtection += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getCollateralDamageProtection() const
{
	return m_iCollateralDamageProtection;
}

void CvUnit::changeCollateralDamageProtection(int iChange)
{
	if (iChange != 0)
	{
		m_iCollateralDamageProtection += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getPillageChange() const
{
	return m_iPillageChange;
}

void CvUnit::changePillageChange(int iChange)
{
	if (iChange != 0)
	{
		m_iPillageChange += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getUpgradeDiscount() const
{
	return m_iUpgradeDiscount;
}

void CvUnit::changeUpgradeDiscount(int iChange)
{
	if (iChange != 0)
	{
		m_iUpgradeDiscount += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getExperiencePercent() const
{
	return m_iExperiencePercent;
}

void CvUnit::changeExperiencePercent(int iChange)
{
	if (iChange != 0)
	{
		m_iExperiencePercent += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getKamikazePercent() const
{
	return m_iKamikazePercent;
}

void CvUnit::changeKamikazePercent(int iChange)
{
	if (iChange != 0)
	{
		m_iKamikazePercent += iChange;

		setInfoBarDirty(true);
	}
}

DirectionTypes CvUnit::getFacingDirection(bool checkLineOfSightProperty) const
{
	if (checkLineOfSightProperty)
	{
		if (m_pUnitInfo->isLineOfSight())
		{
			return m_eFacingDirection; //only look in facing direction
		}
		else
		{
			return NO_DIRECTION; //look in all directions
		}
	}
	else
	{
		return m_eFacingDirection;
	}
}

void CvUnit::setFacingDirection(DirectionTypes eFacingDirection)
{
	if (eFacingDirection != m_eFacingDirection)
	{
		if (m_pUnitInfo->isLineOfSight())
		{
			//remove old fog
			plot()->changeAdjacentSight(getTeam(), visibilityRange(), false, this, true);

			//change direction
			m_eFacingDirection = eFacingDirection;

			//clear new fog
			plot()->changeAdjacentSight(getTeam(), visibilityRange(), true, this, true);

			gDLL->getInterfaceIFace()->setDirty(ColoredPlots_DIRTY_BIT, true);
		}
		else
		{
			m_eFacingDirection = eFacingDirection;
		}

		//update formation
		NotifyEntity(NO_MISSION);
	}
}

void CvUnit::rotateFacingDirectionClockwise()
{
	//change direction
	DirectionTypes eNewDirection = (DirectionTypes) ((m_eFacingDirection + 1) % NUM_DIRECTION_TYPES);
	setFacingDirection(eNewDirection);
}

void CvUnit::rotateFacingDirectionCounterClockwise()
{
	//change direction
	DirectionTypes eNewDirection = (DirectionTypes) ((m_eFacingDirection + NUM_DIRECTION_TYPES - 1) % NUM_DIRECTION_TYPES);
	setFacingDirection(eNewDirection);
}

int CvUnit::getImmobileTimer() const
{
	return m_iImmobileTimer;
}

void CvUnit::setImmobileTimer(int iNewValue)
{
	if (iNewValue != getImmobileTimer())
	{
		m_iImmobileTimer = iNewValue;

		setInfoBarDirty(true);

//FfH: Added by Kael 04/16/2008
        if (getImmobileTimer() == 0)
        {
            if (getDelayedSpell() != NO_SPELL)
            {
                cast(getDelayedSpell());
            }
        }
//FfH: End Add

	}
}

void CvUnit::changeImmobileTimer(int iChange)
{
	if (iChange != 0)
	{
		setImmobileTimer(std::max(0, getImmobileTimer() + iChange));
	}
}

bool CvUnit::isMadeAttack() const
{
	return m_bMadeAttack;
}


void CvUnit::setMadeAttack(bool bNewValue)
{
	m_bMadeAttack = bNewValue;
}


bool CvUnit::isMadeInterception() const
{
	return m_bMadeInterception;
}


void CvUnit::setMadeInterception(bool bNewValue)
{
	m_bMadeInterception = bNewValue;
}


bool CvUnit::isPromotionReady() const
{
	return m_bPromotionReady;
}


void CvUnit::setPromotionReady(bool bNewValue)
{
	if (isPromotionReady() != bNewValue)
	{
		m_bPromotionReady = bNewValue;

		if (m_bPromotionReady)
		{
			getGroup()->setAutomateType(NO_AUTOMATE);
			getGroup()->clearMissionQueue();
			getGroup()->setActivityType(ACTIVITY_AWAKE);
		}

		gDLL->getEntityIFace()->showPromotionGlow(getUnitEntity(), bNewValue);

		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
		}
	}
}


void CvUnit::testPromotionReady()
{
	setPromotionReady((getExperience() >= experienceNeeded()) && canAcquirePromotionAny());
}


bool CvUnit::isDelayedDeath() const
{
	return m_bDeathDelay;
}


void CvUnit::startDelayedDeath()
{
	m_bDeathDelay = true;
}


// Returns true if killed...
bool CvUnit::doDelayedDeath()
{
	if (m_bDeathDelay && !isFighting())
	{
		kill(false);
		return true;
	}

	return false;
}


bool CvUnit::isCombatFocus() const
{
	return m_bCombatFocus;
}


bool CvUnit::isInfoBarDirty() const
{
	return m_bInfoBarDirty;
}


void CvUnit::setInfoBarDirty(bool bNewValue)
{
	m_bInfoBarDirty = bNewValue;
}

bool CvUnit::isBlockading() const
{
	return m_bBlockading;
}

void CvUnit::setBlockading(bool bNewValue)
{
	if (bNewValue != isBlockading())
	{
		m_bBlockading = bNewValue;

		updatePlunder(isBlockading() ? 1 : -1, true);
	}
}

void CvUnit::collectBlockadeGold()
{
	if (plot()->getTeam() == getTeam())
	{
		return;
	}

	int iBlockadeRange = GC.getDefineINT("SHIP_BLOCKADE_RANGE");

	for (int i = -iBlockadeRange; i <= iBlockadeRange; ++i)
	{
		for (int j = -iBlockadeRange; j <= iBlockadeRange; ++j)
		{
			CvPlot* pLoopPlot = ::plotXY(getX_INLINE(), getY_INLINE(), i, j);

			if (NULL != pLoopPlot && pLoopPlot->isRevealed(getTeam(), false))
			{
				CvCity* pCity = pLoopPlot->getPlotCity();

				if (NULL != pCity && !pCity->isPlundered() && isEnemy(pCity->getTeam()) && !atWar(pCity->getTeam(), getTeam()))
				{
					if (pCity->area() == area() || pCity->plot()->isAdjacentToArea(area()))
					{
						int iGold = pCity->calculateTradeProfit(pCity) * pCity->getTradeRoutes();
						if (iGold > 0)
						{
							pCity->setPlundered(true);
							GET_PLAYER(getOwnerINLINE()).changeGold(iGold);
							GET_PLAYER(pCity->getOwnerINLINE()).changeGold(-iGold);

							CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_TRADE_ROUTE_PLUNDERED", getNameKey(), pCity->getNameKey(), iGold);
							gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BUILD_BANK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE());

							szBuffer = gDLL->getText("TXT_KEY_MISC_TRADE_ROUTE_PLUNDER", getNameKey(), pCity->getNameKey(), iGold);
							gDLL->getInterfaceIFace()->addMessage(pCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_BUILD_BANK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCity->getX_INLINE(), pCity->getY_INLINE());
						}
					}
				}
			}
		}
	}
}


PlayerTypes CvUnit::getOwner() const
{
	return getOwnerINLINE();
}

PlayerTypes CvUnit::getVisualOwner(TeamTypes eForTeam) const
{
	if (NO_TEAM == eForTeam)
	{
		eForTeam = GC.getGameINLINE().getActiveTeam();
	}

	if (getTeam() != eForTeam && eForTeam != BARBARIAN_TEAM)
	{

//FfH Hidden Nationality: Modified by Kael 08/27/2007
//		if (m_pUnitInfo->isHiddenNationality())
		if (isHiddenNationality())
//FfH: End Modify

		{
			if (!plot()->isCity(true, getTeam()))
			{
				return BARBARIAN_PLAYER;
			}
		}
	}

	return getOwnerINLINE();
}


PlayerTypes CvUnit::getCombatOwner(TeamTypes eForTeam, const CvPlot* pPlot) const
{
	if (eForTeam != NO_TEAM && getTeam() != eForTeam && eForTeam != BARBARIAN_TEAM)
	{
		if (isAlwaysHostile(pPlot))
		{
			return BARBARIAN_PLAYER;
		}
	}

	return getOwnerINLINE();
}

TeamTypes CvUnit::getTeam() const
{
	return GET_PLAYER(getOwnerINLINE()).getTeam();
}


PlayerTypes CvUnit::getCapturingPlayer() const
{
	return m_eCapturingPlayer;
}


void CvUnit::setCapturingPlayer(PlayerTypes eNewValue)
{

//FfH: Modified by Kael 08/12/2007
//	m_eCapturingPlayer = eNewValue;
    if (!isImmuneToCapture())
    {
        m_eCapturingPlayer = eNewValue;
    }
//FfH: End Add

}


const UnitTypes CvUnit::getUnitType() const
{
	return m_eUnitType;
}

CvUnitInfo &CvUnit::getUnitInfo() const
{
	return *m_pUnitInfo;
}


UnitClassTypes CvUnit::getUnitClassType() const
{
	return (UnitClassTypes)m_pUnitInfo->getUnitClassType();
}

const UnitTypes CvUnit::getLeaderUnitType() const
{
	return m_eLeaderUnitType;
}

void CvUnit::setLeaderUnitType(UnitTypes leaderUnitType)
{
	if(m_eLeaderUnitType != leaderUnitType)
	{
		m_eLeaderUnitType = leaderUnitType;
		reloadEntity();
	}
}

CvUnit* CvUnit::getCombatUnit() const
{
	return getUnit(m_combatUnit);
}


void CvUnit::setCombatUnit(CvUnit* pCombatUnit, bool bAttacking)
{
	if (isCombatFocus())
	{
		gDLL->getInterfaceIFace()->setCombatFocus(false);
	}

	if (pCombatUnit != NULL)
	{
		if (bAttacking)
		{
			if (GC.getLogging())
			{
				if (gDLL->getChtLvl() > 0)
				{
					// Log info about this combat...
					char szOut[1024];
					sprintf( szOut, "*** KOMBAT!\n     ATTACKER: Player %d Unit %d (%S's %S), CombatStrength=%d\n     DEFENDER: Player %d Unit %d (%S's %S), CombatStrength=%d\n",
						getOwnerINLINE(), getID(), GET_PLAYER(getOwnerINLINE()).getName(), getName().GetCString(), currCombatStr(NULL, NULL),
						pCombatUnit->getOwnerINLINE(), pCombatUnit->getID(), GET_PLAYER(pCombatUnit->getOwnerINLINE()).getName(), pCombatUnit->getName().GetCString(), pCombatUnit->currCombatStr(pCombatUnit->plot(), this));
					gDLL->messageControlLog(szOut);
				}
			}

			if (getDomainType() == DOMAIN_LAND
				&& !m_pUnitInfo->isIgnoreBuildingDefense()
				&& pCombatUnit->plot()->getPlotCity()
				&& pCombatUnit->plot()->getPlotCity()->getBuildingDefense() > 0
				&& cityAttackModifier() >= GC.getDefineINT("MIN_CITY_ATTACK_MODIFIER_FOR_SIEGE_TOWER"))
			{
				CvDLLEntity::SetSiegeTower(true);
			}
		}

		FAssertMsg(getCombatUnit() == NULL, "Combat Unit is not expected to be assigned");
		FAssertMsg(!(plot()->isFighting()), "(plot()->isFighting()) did not return false as expected");
		m_bCombatFocus = (bAttacking && !(gDLL->getInterfaceIFace()->isFocusedWidget()) && ((getOwnerINLINE() == GC.getGameINLINE().getActivePlayer()) || ((pCombatUnit->getOwnerINLINE() == GC.getGameINLINE().getActivePlayer()) && !(GC.getGameINLINE().isMPOption(MPOPTION_SIMULTANEOUS_TURNS)))));
		m_combatUnit = pCombatUnit->getIDInfo();
		setCombatFirstStrikes((pCombatUnit->immuneToFirstStrikes()) ? 0 : (firstStrikes() + GC.getGameINLINE().getSorenRandNum(chanceFirstStrikes() + 1, "First Strike")));
		setCombatDamage(0);
	}
	else
	{
		if(getCombatUnit() != NULL)
		{
			FAssertMsg(getCombatUnit() != NULL, "getCombatUnit() is not expected to be equal with NULL");
			FAssertMsg(plot()->isFighting(), "plot()->isFighting is expected to be true");
			m_bCombatFocus = false;
			m_combatUnit.reset();
			setCombatFirstStrikes(0);
			setCombatDamage(0);

			if (IsSelected())
			{
				gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
			}

			if (plot() == gDLL->getInterfaceIFace()->getSelectionPlot())
			{
				gDLL->getInterfaceIFace()->setDirty(PlotListButtons_DIRTY_BIT, true);
			}

			CvDLLEntity::SetSiegeTower(false);
		}
	}

	setCombatTimer(0);
	setInfoBarDirty(true);

	if (isCombatFocus())
	{
		gDLL->getInterfaceIFace()->setCombatFocus(true);
	}
}


CvUnit* CvUnit::getTransportUnit() const
{
	return getUnit(m_transportUnit);
}


bool CvUnit::isCargo() const
{
	return (getTransportUnit() != NULL);
}


void CvUnit::setTransportUnit(CvUnit* pTransportUnit)
{
	CvUnit* pOldTransportUnit;

	pOldTransportUnit = getTransportUnit();

	if (pOldTransportUnit != pTransportUnit)
	{
		if (pOldTransportUnit != NULL)
		{
			pOldTransportUnit->changeCargo(-1);
		}

		if (pTransportUnit != NULL)
		{
			FAssertMsg(pTransportUnit->cargoSpaceAvailable(getSpecialUnitType(), getDomainType()) > 0, "Cargo space is expected to be available");

			joinGroup(NULL, true); // Because what if a group of 3 tries to get in a transport which can hold 2...

			m_transportUnit = pTransportUnit->getIDInfo();

			if (getDomainType() != DOMAIN_AIR)
			{
				getGroup()->setActivityType(ACTIVITY_SLEEP);
			}

			if (GC.getGameINLINE().isFinalInitialized())
			{
				finishMoves();
			}

			pTransportUnit->changeCargo(1);
			pTransportUnit->getGroup()->setActivityType(ACTIVITY_AWAKE);
		}
		else
		{
			m_transportUnit.reset();

			getGroup()->setActivityType(ACTIVITY_AWAKE);
		}
	}
}


int CvUnit::getExtraDomainModifier(DomainTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < NUM_DOMAIN_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_aiExtraDomainModifier[eIndex];
}


void CvUnit::changeExtraDomainModifier(DomainTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < NUM_DOMAIN_TYPES, "eIndex is expected to be within maximum bounds (invalid Index)");
	m_aiExtraDomainModifier[eIndex] = (m_aiExtraDomainModifier[eIndex] + iChange);
}


const CvWString CvUnit::getName(uint uiForm) const
{
	CvWString szBuffer;

	if (isEmpty(m_szName))
	{
		return m_pUnitInfo->getDescription(uiForm);
	}

	szBuffer.Format(L"%s (%s)", m_szName.GetCString(), m_pUnitInfo->getDescription(uiForm));

	return szBuffer;
}


const wchar* CvUnit::getNameKey() const
{
	if (isEmpty(m_szName))
	{
		return m_pUnitInfo->getTextKeyWide();
	}
	else
	{
		return m_szName.GetCString();
	}
}


const CvWString CvUnit::getNameNoDesc() const
{
	return m_szName.GetCString();
}


void CvUnit::setName(CvWString szNewValue)
{
	gDLL->stripSpecialCharacters(szNewValue);

	m_szName = szNewValue;

	if (IsSelected())
	{
		gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
	}
}


std::string CvUnit::getScriptData() const
{
	return m_szScriptData;
}


void CvUnit::setScriptData(std::string szNewValue)
{
	m_szScriptData = szNewValue;
}


int CvUnit::getTerrainDoubleMoveCount(TerrainTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiTerrainDoubleMoveCount[eIndex];
}


bool CvUnit::isTerrainDoubleMove(TerrainTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return (getTerrainDoubleMoveCount(eIndex) > 0);
}


void CvUnit::changeTerrainDoubleMoveCount(TerrainTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	m_paiTerrainDoubleMoveCount[eIndex] = (m_paiTerrainDoubleMoveCount[eIndex] + iChange);
	FAssert(getTerrainDoubleMoveCount(eIndex) >= 0);
}


int CvUnit::getFeatureDoubleMoveCount(FeatureTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiFeatureDoubleMoveCount[eIndex];
}


bool CvUnit::isFeatureDoubleMove(FeatureTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return (getFeatureDoubleMoveCount(eIndex) > 0);
}


void CvUnit::changeFeatureDoubleMoveCount(FeatureTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	m_paiFeatureDoubleMoveCount[eIndex] = (m_paiFeatureDoubleMoveCount[eIndex] + iChange);
	FAssert(getFeatureDoubleMoveCount(eIndex) >= 0);
}


int CvUnit::getExtraTerrainAttackPercent(TerrainTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiExtraTerrainAttackPercent[eIndex];
}


void CvUnit::changeExtraTerrainAttackPercent(TerrainTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_paiExtraTerrainAttackPercent[eIndex] += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getExtraTerrainDefensePercent(TerrainTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiExtraTerrainDefensePercent[eIndex];
}


void CvUnit::changeExtraTerrainDefensePercent(TerrainTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumTerrainInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_paiExtraTerrainDefensePercent[eIndex] += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getExtraFeatureAttackPercent(FeatureTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiExtraFeatureAttackPercent[eIndex];
}


void CvUnit::changeExtraFeatureAttackPercent(FeatureTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_paiExtraFeatureAttackPercent[eIndex] += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getExtraFeatureDefensePercent(FeatureTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiExtraFeatureDefensePercent[eIndex];
}


void CvUnit::changeExtraFeatureDefensePercent(FeatureTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumFeatureInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");

	if (iChange != 0)
	{
		m_paiExtraFeatureDefensePercent[eIndex] += iChange;

		setInfoBarDirty(true);
	}
}

int CvUnit::getExtraUnitCombatModifier(UnitCombatTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_paiExtraUnitCombatModifier[eIndex];
}


void CvUnit::changeExtraUnitCombatModifier(UnitCombatTypes eIndex, int iChange)
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumUnitCombatInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	m_paiExtraUnitCombatModifier[eIndex] = (m_paiExtraUnitCombatModifier[eIndex] + iChange);
}


bool CvUnit::canAcquirePromotion(PromotionTypes ePromotion) const
{
	FAssertMsg(ePromotion >= 0, "ePromotion is expected to be non-negative (invalid Index)");
	FAssertMsg(ePromotion < GC.getNumPromotionInfos(), "ePromotion is expected to be within maximum bounds (invalid Index)");

	if (isHasPromotion(ePromotion))
	{
		return false;
	}

	if (GC.getPromotionInfo(ePromotion).getPrereqPromotion() != NO_PROMOTION)
	{
		if (!isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPrereqPromotion())))
		{
			return false;
		}
	}

//FfH: Modified by Kael 07/30/2007
//	if (GC.getPromotionInfo(ePromotion).getPrereqOrPromotion1() != NO_PROMOTION)
//	{
//		if (!isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPrereqOrPromotion1())))
//		{
//			if ((GC.getPromotionInfo(ePromotion).getPrereqOrPromotion2() == NO_PROMOTION) || !isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPrereqOrPromotion2())))
//			{
//				return false;
//			}
//		}
//	}
	if (GC.getPromotionInfo(ePromotion).getPromotionPrereqAnd() != NO_PROMOTION)
	{
		if (!isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPromotionPrereqAnd())))
		{
			return false;
		}
	}
	if (GC.getPromotionInfo(ePromotion).getPrereqOrPromotion1() != NO_PROMOTION)
	{
	    bool bValid = false;
		if (isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPrereqOrPromotion1())))
		{
		    bValid = true;
		}
        if (GC.getPromotionInfo(ePromotion).getPrereqOrPromotion2() != NO_PROMOTION)
        {
            if (isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPrereqOrPromotion2())))
            {
                bValid = true;
            }
        }
        if (GC.getPromotionInfo(ePromotion).getPromotionPrereqOr3() != NO_PROMOTION)
        {
            if (isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPromotionPrereqOr3())))
            {
                bValid = true;
            }
        }
        if (GC.getPromotionInfo(ePromotion).getPromotionPrereqOr4() != NO_PROMOTION)
        {
            if (isHasPromotion((PromotionTypes)(GC.getPromotionInfo(ePromotion).getPromotionPrereqOr4())))
            {
                bValid = true;
            }
        }
        if (!bValid)
        {
            return false;
        }
	}
	if (GC.getPromotionInfo(ePromotion).getBonusPrereq() != NO_BONUS)
	{
	    if (!GET_PLAYER(getOwnerINLINE()).hasBonus((BonusTypes)GC.getPromotionInfo(ePromotion).getBonusPrereq()))
	    {
	        return false;
	    }
	}
    for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
    {
        if (isHasPromotion((PromotionTypes)iI))
        {
            if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionImmune1() == ePromotion)
            {
                return false;
            }
            if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionImmune2() == ePromotion)
            {
                return false;
            }
            if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionImmune3() == ePromotion)
            {
                return false;
            }
        }
    }
	if (GC.getPromotionInfo(ePromotion).isPrereqAlive())
	{
	    if (!isAlive())
	    {
	        return false;
	    }
	}
//FfH: End Add

	if (GC.getPromotionInfo(ePromotion).getTechPrereq() != NO_TECH)
	{
		if (!(GET_TEAM(getTeam()).isHasTech((TechTypes)(GC.getPromotionInfo(ePromotion).getTechPrereq()))))
		{
			return false;
		}
	}

	if (GC.getPromotionInfo(ePromotion).getStateReligionPrereq() != NO_RELIGION)
	{
		if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != GC.getPromotionInfo(ePromotion).getStateReligionPrereq())
		{
			return false;
		}
	}

/*************************************************************************************************/
/**	MinLevel						05/20/08										Xienwolf	**/
/**																								**/
/**					Requires Unit Level be Sufficient for the Promotion							**/
/*************************************************************************************************/
    if (GC.getPromotionInfo(ePromotion).getPreReqLevel() != 0)
    {
        if (GC.getPromotionInfo(ePromotion).getPreReqLevel() < 0 || getLevel() < GC.getPromotionInfo(ePromotion).getPreReqLevel())
        {
            return false;
        }
    }
/*************************************************************************************************/
/**	MinLevel									END												**/
/*************************************************************************************************/
	if (!isPromotionValid(ePromotion))
	{
		return false;
	}

	return true;
}

bool CvUnit::isPromotionValid(PromotionTypes ePromotion) const
{
	if (!::isPromotionValid(ePromotion, getUnitType(), true))
	{
		return false;
	}

/*************************************************************************************************/
/**	AttackEnable					05/20/08										Xienwolf	**/
/**																								**/
/**				Need to call this on the Unit for proper Logic Check now						**/
/*************************************************************************************************/
	if (GC.getUnitInfo(getUnitType()).isOnlyDefensive() && !isAllowAttacks() && !GC.getPromotionInfo(ePromotion).isAllowAttacks())
	{
		if ((GC.getPromotionInfo(ePromotion).getCityAttackPercent() != 0) ||
			  (GC.getPromotionInfo(ePromotion).getWithdrawalChange() != 0) ||
			  (GC.getPromotionInfo(ePromotion).getCollateralDamageChange() != 0) ||
			  (GC.getPromotionInfo(ePromotion).isBlitz()) ||
			  (GC.getPromotionInfo(ePromotion).isAmphib()) ||
			  (GC.getPromotionInfo(ePromotion).isRiver()) ||
			  (GC.getPromotionInfo(ePromotion).getHillsAttackPercent() != 0))
		{
			return false;
		}
	}
/*************************************************************************************************/
/**	AttackEnable								END												**/
/*************************************************************************************************/
/*************************************************************************************************/
/**	MoveBetter						05/20/08										Xienwolf	**/
/**																								**/
/**				Need to call this on the Unit for proper Logic Check now						**/
/*************************************************************************************************/
	if (GC.getUnitInfo(getUnitType()).isIgnoreTerrainCost() && !isIgnoreTerrainCosts())
	{
		if (GC.getPromotionInfo(ePromotion).getMoveDiscountChange() != 0)
		{
			return false;
		}
	}
/*************************************************************************************************/
/**	MoveBetter									END												**/
/*************************************************************************************************/
	CvPromotionInfo& promotionInfo = GC.getPromotionInfo(ePromotion);

	if (promotionInfo.getWithdrawalChange() + withdrawalProbability() > GC.getDefineINT("MAX_WITHDRAWAL_PROBABILITY"))
	{
		return false;
	}

	if (promotionInfo.getInterceptChange() + maxInterceptionProbability() > GC.getDefineINT("MAX_INTERCEPTION_PROBABILITY"))
	{
		return false;
	}

	if (promotionInfo.getEvasionChange() + evasionProbability() > GC.getDefineINT("MAX_EVASION_PROBABILITY"))
	{
		return false;
	}

	return true;
}


bool CvUnit::canAcquirePromotionAny() const
{
	int iI;

	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		if (canAcquirePromotion((PromotionTypes)iI))
		{
			return true;
		}
	}

	return false;
}


bool CvUnit::isHasPromotion(PromotionTypes eIndex) const
{
	FAssertMsg(eIndex >= 0, "eIndex is expected to be non-negative (invalid Index)");
	FAssertMsg(eIndex < GC.getNumPromotionInfos(), "eIndex is expected to be within maximum bounds (invalid Index)");
	return m_pabHasPromotion[eIndex];
}


void CvUnit::setHasPromotion(PromotionTypes eIndex, bool bNewValue)
{
	int iChange;
	int iI;

	if (isHasPromotion(eIndex) != bNewValue)
/*************************************************************************************************/
/**	Xienwolf Notes								NOTES											**/
/**						If the Unit does not already Have (not Have) the Promotion				**/
/**						then the following happens to update Data as instructed					**/
/*************************************************************************************************/
	{
		m_pabHasPromotion[eIndex] = bNewValue;

		iChange = ((isHasPromotion(eIndex)) ? 1 : -1);

		changeBlitzCount((GC.getPromotionInfo(eIndex).isBlitz()) ? iChange : 0);
		changeAmphibCount((GC.getPromotionInfo(eIndex).isAmphib()) ? iChange : 0);
		changeRiverCount((GC.getPromotionInfo(eIndex).isRiver()) ? iChange : 0);
/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**						Loads Promotion Information onto the Unit Insformation  		        **/
/*************************************************************************************************/
		changeTerritorialCount((GC.getPromotionInfo(eIndex).isTerritorial()) ? iChange : 0);
		changeRivalTerritoryExploreCount((GC.getPromotionInfo(eIndex).isRivalTerritoryExplore()) ? iChange : 0);
		changeRivalTerritoryBlockCount((GC.getPromotionInfo(eIndex).isRivalTerritoryBlock()) ? iChange : 0);
		changePillageOnMoveCount((GC.getPromotionInfo(eIndex).isPillageOnMove()) ? iChange : 0);
		changeSelfPillageCount((GC.getPromotionInfo(eIndex).isSelfPillage()) ? iChange : 0);
		changeGetCasterXPCount((GC.getPromotionInfo(eIndex).isGetCasterXP()) ? iChange : 0);
		changeNonWarWearinessCount((GC.getPromotionInfo(eIndex).isNonWarWeariness()) ? iChange : 0);
		changeNoMapRevealCount((GC.getPromotionInfo(eIndex).isNoMapReveal()) ? iChange : 0);
		changeCannotCaptureCount((GC.getPromotionInfo(eIndex).isCannotCapture()) ? iChange : 0);
		changeCityHappyCount((GC.getPromotionInfo(eIndex).isCityHappy()) ? iChange : 0);
		changeCityNoHappyCount((GC.getPromotionInfo(eIndex).isCityNoHappy()) ? iChange : 0);
		changeNoSupportCount((GC.getPromotionInfo(eIndex).isNoSupport()) ? iChange : 0);
		changeCanPillageCount((GC.getPromotionInfo(eIndex).isCanPillage()) ? iChange : 0);
		changeCannotPillageCount((GC.getPromotionInfo(eIndex).isCannotPillage()) ? iChange : 0);
		changeCitySpyCount((GC.getPromotionInfo(eIndex).isCitySpy()) ? iChange : 0);
		changeStartGoldenAgeCount((GC.getPromotionInfo(eIndex).isStartGoldenAge()) ? iChange : 0);
		changeNoDefenseBonusCount((GC.getPromotionInfo(eIndex).isNoDefenseBonus()) ? iChange : 0);
		changeMoveImpassableCount((GC.getPromotionInfo(eIndex).isMoveImpassable()) ? iChange : 0);
		changeFlatMoveCostCount((GC.getPromotionInfo(eIndex).isFlatMoveCost()) ? iChange : 0);
		changeIgnoreTerrainCostsCount((GC.getPromotionInfo(eIndex).isIgnoreTerrainCosts()) ? iChange : 0);
		changeAttackNoWarCount((GC.getPromotionInfo(eIndex).isAttackNoWar()) ? iChange : 0);
		changeAllowAttacksCount((GC.getPromotionInfo(eIndex).isAllowAttacks()) ? iChange : 0);
		changeFirstStrikeVulnerableCount((GC.getPromotionInfo(eIndex).isFirstStrikeVulnerable()) ? iChange : 0);
		changeAllowDefenseBonusesCount((GC.getPromotionInfo(eIndex).isAllowDefenseBonuses()) ? iChange : 0);
		changeNonAbandonCount((GC.getPromotionInfo(eIndex).isNonAbandon()) ? iChange : 0);
		changeIndependantCount((GC.getPromotionInfo(eIndex).isIndependant()) ? iChange : 0);

		changeWorkRateChange(GC.getPromotionInfo(eIndex).getWorkRateChange() * iChange);
		changeCombatConversionChance(GC.getPromotionInfo(eIndex).getCombatConversionChance() * iChange);
		changeCombatUnitGenerationChance(GC.getPromotionInfo(eIndex).getCombatUnitGenerationChance() * iChange);
		changeSlaveGenerationChance(GC.getPromotionInfo(eIndex).getSlaveGenerationChance() * iChange);
		changeGiftableXP(GC.getPromotionInfo(eIndex).getGiftableXP() * iChange);
		changeCombatExtraDuration(GC.getPromotionInfo(eIndex).getCombatExtraDuration() * iChange);
		changeDurationPerTurn(GC.getPromotionInfo(eIndex).getDurationPerTurn() * iChange);
		changeDurationAlter(GC.getPromotionInfo(eIndex).getDurationAlter() * iChange);
		changeChangeDuration(GC.getPromotionInfo(eIndex).getChangeDuration() * iChange);
		changeExtraSupport(GC.getPromotionInfo(eIndex).getExtraSupport() * iChange);
		changeChanceMiscast(GC.getPromotionInfo(eIndex).getChanceMiscast() * iChange);
		changeCombatDmgCap(GC.getPromotionInfo(eIndex).getCombatDmgCap() * iChange);
		changeCombatDmgCapBoost(GC.getPromotionInfo(eIndex).getCombatDmgCapBoost() * iChange);
		changeCollateralLimitCap(GC.getPromotionInfo(eIndex).getCollateralLimitCap() * iChange);
		changeCollateralLimitBoost(GC.getPromotionInfo(eIndex).getCollateralLimitBoost() * iChange);
		changeCollateralTargetsLimit(GC.getPromotionInfo(eIndex).getCollateralTargetsLimit() * iChange);
		changeCollateralExtraTargets(GC.getPromotionInfo(eIndex).getCollateralExtraTargets() * iChange);
		changeHammerSacrifice(GC.getPromotionInfo(eIndex).getHammerSacrifice() * iChange);
		changeExtraHammerPerPop(GC.getPromotionInfo(eIndex).getExtraHammerPerPop() * iChange);
		changeFoodSacrifice(GC.getPromotionInfo(eIndex).getFoodSacrifice() * iChange);
		changePopulationAdd(GC.getPromotionInfo(eIndex).getPopulationAdd() * iChange);
		changeBeakerSacrifice(GC.getPromotionInfo(eIndex).getBeakerSacrifice() * iChange);
		changeExtraBeakerPerPop(GC.getPromotionInfo(eIndex).getExtraBeakerPerPop() * iChange);
		changeGoldSacrifice(GC.getPromotionInfo(eIndex).getGoldSacrifice() * iChange);
		changeExtraGoldPerPop(GC.getPromotionInfo(eIndex).getExtraGoldPerPop() * iChange);
		changeCultureSacrifice(GC.getPromotionInfo(eIndex).getCultureSacrifice() * iChange);
		changeExtraCulturePerPop(GC.getPromotionInfo(eIndex).getExtraCulturePerPop() * iChange);

		for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
		{
			changeYieldFromWin(iI, (GC.getPromotionInfo(eIndex).getYieldFromWin(iI) * iChange));
			changeYieldForLoss(iI, (GC.getPromotionInfo(eIndex).getYieldForLoss(iI) * iChange));
		}

		for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
		{
			changeCommerceFromWin(iI, (GC.getPromotionInfo(eIndex).getCommerceFromWin(iI) * iChange));
			changeCommerceForLoss(iI, (GC.getPromotionInfo(eIndex).getCommerceForLoss(iI) * iChange));
		}
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
		changeEnemyRouteCount((GC.getPromotionInfo(eIndex).isEnemyRoute()) ? iChange : 0);
		changeAlwaysHealCount((GC.getPromotionInfo(eIndex).isAlwaysHeal()) ? iChange : 0);
		changeHillsDoubleMoveCount((GC.getPromotionInfo(eIndex).isHillsDoubleMove()) ? iChange : 0);
		changeImmuneToFirstStrikesCount((GC.getPromotionInfo(eIndex).isImmuneToFirstStrikes()) ? iChange : 0);

		changeExtraVisibilityRange(GC.getPromotionInfo(eIndex).getVisibilityChange() * iChange);
		changeExtraMoves(GC.getPromotionInfo(eIndex).getMovesChange() * iChange);
		changeExtraMoveDiscount(GC.getPromotionInfo(eIndex).getMoveDiscountChange() * iChange);
		changeExtraAirRange(GC.getPromotionInfo(eIndex).getAirRangeChange() * iChange);
		changeExtraIntercept(GC.getPromotionInfo(eIndex).getInterceptChange() * iChange);
		changeExtraEvasion(GC.getPromotionInfo(eIndex).getEvasionChange() * iChange);
		changeExtraFirstStrikes(GC.getPromotionInfo(eIndex).getFirstStrikesChange() * iChange);
		changeExtraChanceFirstStrikes(GC.getPromotionInfo(eIndex).getChanceFirstStrikesChange() * iChange);
		changeExtraWithdrawal(GC.getPromotionInfo(eIndex).getWithdrawalChange() * iChange);
		changeExtraCollateralDamage(GC.getPromotionInfo(eIndex).getCollateralDamageChange() * iChange);
		changeExtraBombardRate(GC.getPromotionInfo(eIndex).getBombardRateChange() * iChange);
		changeExtraEnemyHeal(GC.getPromotionInfo(eIndex).getEnemyHealChange() * iChange);
		changeExtraNeutralHeal(GC.getPromotionInfo(eIndex).getNeutralHealChange() * iChange);
		changeExtraFriendlyHeal(GC.getPromotionInfo(eIndex).getFriendlyHealChange() * iChange);
		changeSameTileHeal(GC.getPromotionInfo(eIndex).getSameTileHealChange() * iChange);
		changeAdjacentTileHeal(GC.getPromotionInfo(eIndex).getAdjacentTileHealChange() * iChange);
		changeExtraCombatPercent(GC.getPromotionInfo(eIndex).getCombatPercent() * iChange);
		changeExtraCityAttackPercent(GC.getPromotionInfo(eIndex).getCityAttackPercent() * iChange);
		changeExtraCityDefensePercent(GC.getPromotionInfo(eIndex).getCityDefensePercent() * iChange);
		changeExtraHillsAttackPercent(GC.getPromotionInfo(eIndex).getHillsAttackPercent() * iChange);
		changeExtraHillsDefensePercent(GC.getPromotionInfo(eIndex).getHillsDefensePercent() * iChange);
		changeRevoltProtection(GC.getPromotionInfo(eIndex).getRevoltProtection() * iChange);
		changeCollateralDamageProtection(GC.getPromotionInfo(eIndex).getCollateralDamageProtection() * iChange);
		changePillageChange(GC.getPromotionInfo(eIndex).getPillageChange() * iChange);
		changeUpgradeDiscount(GC.getPromotionInfo(eIndex).getUpgradeDiscount() * iChange);
		changeExperiencePercent(GC.getPromotionInfo(eIndex).getExperiencePercent() * iChange);
		changeKamikazePercent((GC.getPromotionInfo(eIndex).getKamikazePercent()) * iChange);
		changeCargoSpace(GC.getPromotionInfo(eIndex).getCargoChange() * iChange);

//FfH: Added by Kael 07/30/2007
		changeBaseCombatStr(GC.getPromotionInfo(eIndex).getExtraCombatStr() * iChange);
		changeBaseCombatStrDefense(GC.getPromotionInfo(eIndex).getExtraCombatDefense() * iChange);
		changeBetterDefenderThanPercent(GC.getPromotionInfo(eIndex).getBetterDefenderThanPercent() * iChange);
		changeCombatHealPercent(GC.getPromotionInfo(eIndex).getCombatHealPercent() * iChange);
		changeCombatPercentInBorders(GC.getPromotionInfo(eIndex).getCombatPercentInBorders() * iChange);
		changeCombatPercentGlobalCounter(GC.getPromotionInfo(eIndex).getCombatPercentGlobalCounter() * iChange);
		changeResist(GC.getPromotionInfo(eIndex).getResistMagic() * iChange);
		changeResistModify(GC.getPromotionInfo(eIndex).getCasterResistModify() * iChange);
		changeResistModify(GC.getPromotionInfo(eIndex).getCasterResistModify() * iChange);
		changeSpellCasterXP(GC.getPromotionInfo(eIndex).getSpellCasterXP() * iChange);
		changeSpellDamageModify(GC.getPromotionInfo(eIndex).getSpellDamageModify() * iChange);
        GC.getGameINLINE().changeGlobalCounter(GC.getPromotionInfo(eIndex).getModifyGlobalCounter() * iChange);
        if (GC.getPromotionInfo(eIndex).getCombatLimit() != 0)
        {
            calcCombatLimit();
        }
/*************************************************************************************************/
/**	MilSupport (PromotionInfos)		05/15/08										Xienwolf	**/
/**				Changes Military Support Costs upon Gaining or Losing this Promotion Flag		**/
/**																								**/
/**	MilHappy (PromotionInfos)		05/15/08										Xienwolf	**/
/**	Updates the Military Happiness when Promotions are Gained while the Unit is on a City Tile	**/
/**																								**/
/**	Independance (PromotionInfos)	05/15/08										Xienwolf	**/
/**						Alters the Unitcount When promotion is Granted or Lost					**/
/**	Upkeep							05/20/08										Xienwolf	**/
/**																								**/
/*************************************************************************************************/
        if (GC.getPromotionInfo(eIndex).isNoSupport())
        {
            if (bNewValue)
                GET_PLAYER(getOwnerINLINE()).changeNumMilitaryUnits(-1);
            else
                GET_PLAYER(getOwnerINLINE()).changeNumMilitaryUnits(1);
        }
        if (GC.getPromotionInfo(eIndex).isCityHappy())
            if (plot()->isCity())
                plot()->getPlotCity()->changeMilitaryHappinessUnits(1);
        if (GC.getPromotionInfo(eIndex).isCityNoHappy())
            if (plot()->isCity())
                plot()->getPlotCity()->changeMilitaryHappinessUnits(-1);
        if (GC.getPromotionInfo(eIndex).isIndependant())
        {
            if (bNewValue)
            {
                GET_TEAM(getTeam()).changeUnitClassCount((UnitClassTypes)m_pUnitInfo->getUnitClassType(), -1);
                GET_PLAYER(getOwnerINLINE()).changeUnitClassCount((UnitClassTypes)m_pUnitInfo->getUnitClassType(), -1);
            }
            else
            {
                GET_TEAM(getTeam()).changeUnitClassCount(((UnitClassTypes)(m_pUnitInfo->getUnitClassType())), 1);
                GET_PLAYER(getOwnerINLINE()).changeUnitClassCount(((UnitClassTypes)(m_pUnitInfo->getUnitClassType())), 1);
            }
        }
        if (GC.getPromotionInfo(eIndex).getExtraSupport() != 0)
        {
            GET_PLAYER(getOwnerINLINE()).changeUpkeepCosts(GC.getPromotionInfo(eIndex).getExtraSupport() * iChange);
        }
/*************************************************************************************************/
/**	MilSupport (PromotionInfos)					END												**/
/**	MilHappy (PromotionInfos)					END												**/
/**	Independance (PromotionInfos)				END												**/
/**	Upkeep										END												**/
/*************************************************************************************************/
        if (GC.getPromotionInfo(eIndex).isDoubleFortifyBonus())
        {
            setDoubleFortifyBonus(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isBoarding())
        {
            setBoarding(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isFear())
        {
            setFear(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isFlying())
        {
            setFlying(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isHiddenNationality())
        {
            setHiddenNationality(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isIgnoreBuildingDefense())
        {
            setIgnoreBuildingDefense(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isImmortal())
        {
            setImmortal(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isImmuneToCapture())
        {
            setImmuneToCapture(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isImmuneToFear())
        {
            setImmuneToFear(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isImmuneToMagic())
        {
            setImmuneToMagic(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isInvisible())
        {
            if (bNewValue)
            {
                setInvisibleType(GC.getDefineINT("INVISIBLE_TYPE"));
            }
            else
            {
                setInvisibleType(NO_INVISIBLE);
            }
        }
        if (eIndex == GC.getDefineINT("MUTATED_PROMOTION") && bNewValue)
        {
            mutate();
        }
        if (GC.getPromotionInfo(eIndex).isOnlyDefensive())
        {
            setOnlyDefensive(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isRace())
        {
            if (bNewValue)
            {
                setRace(eIndex);
            }
            else
            {
                setRace(NO_PROMOTION);
            }
        }
        if (GC.getPromotionInfo(eIndex).isTargetWeakestUnit())
        {
            setTargetWeakestUnit(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isTargetWeakestUnitCounter())
        {
            setTargetWeakestUnitCounter(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isTwincast())
        {
            setTwincast(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isWaterWalking())
        {
            setWaterWalking(bNewValue);
        }
        if (GC.getPromotionInfo(eIndex).isNotAlive())
        {
            setAlive(false);
        }
		for (iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
		{
			changeDamageTypeCombat(((DamageTypes)iI), (GC.getPromotionInfo(eIndex).getDamageTypeCombat(iI) * iChange));
		}
		for (iI = 0; iI < GC.getNumBonusInfos(); iI++)
		{
			changeBonusAffinity(((BonusTypes)iI), (GC.getPromotionInfo(eIndex).getBonusAffinity(iI) * iChange));
		}
		for (iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
		{
			changeDamageTypeResist(((DamageTypes)iI), (GC.getPromotionInfo(eIndex).getDamageTypeResist(iI) * iChange));
		}
        if (GC.getPromotionInfo(eIndex).getUnitArtStyleType() != NO_UNIT_ARTSTYLE)
        {
            if (iChange > 0)
            {
                setUnitArtStyleType(GC.getPromotionInfo(eIndex).getUnitArtStyleType());
            }
            else
            {
                if (GC.getPromotionInfo(eIndex).getUnitArtStyleType() == getUnitArtStyleType())
                {
                    setUnitArtStyleType(NO_UNIT_ARTSTYLE);
                }
            }
            reloadEntity();
        }
        if (GC.getPromotionInfo(eIndex).getGroupSize() != 0)
        {
            if (bNewValue)
            {
                setGroupSize(GC.getPromotionInfo(eIndex).getGroupSize());
            }
            else
            {
                setGroupSize(0);
            }
            reloadEntity();
        }
//FfH: End Add

		for (iI = 0; iI < GC.getNumTerrainInfos(); iI++)
		{
			changeExtraTerrainAttackPercent(((TerrainTypes)iI), (GC.getPromotionInfo(eIndex).getTerrainAttackPercent(iI) * iChange));
			changeExtraTerrainDefensePercent(((TerrainTypes)iI), (GC.getPromotionInfo(eIndex).getTerrainDefensePercent(iI) * iChange));
			changeTerrainDoubleMoveCount(((TerrainTypes)iI), ((GC.getPromotionInfo(eIndex).getTerrainDoubleMove(iI)) ? iChange : 0));
		}

		for (iI = 0; iI < GC.getNumFeatureInfos(); iI++)
		{
			changeExtraFeatureAttackPercent(((FeatureTypes)iI), (GC.getPromotionInfo(eIndex).getFeatureAttackPercent(iI) * iChange));
			changeExtraFeatureDefensePercent(((FeatureTypes)iI), (GC.getPromotionInfo(eIndex).getFeatureDefensePercent(iI) * iChange));
			changeFeatureDoubleMoveCount(((FeatureTypes)iI), ((GC.getPromotionInfo(eIndex).getFeatureDoubleMove(iI)) ? iChange : 0));
		}

		for (iI = 0; iI < GC.getNumUnitCombatInfos(); iI++)
		{
			changeExtraUnitCombatModifier(((UnitCombatTypes)iI), (GC.getPromotionInfo(eIndex).getUnitCombatModifierPercent(iI) * iChange));
		}

		for (iI = 0; iI < NUM_DOMAIN_TYPES; iI++)
		{
			changeExtraDomainModifier(((DomainTypes)iI), (GC.getPromotionInfo(eIndex).getDomainModifierPercent(iI) * iChange));
		}

		if (IsSelected())
		{
			gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
			gDLL->getInterfaceIFace()->setDirty(InfoPane_DIRTY_BIT, true);
		}

		//update graphics
		gDLL->getEntityIFace()->updatePromotionLayers(getUnitEntity());
	}
}


int CvUnit::getSubUnitCount() const
{
	return m_pUnitInfo->getGroupSize();
}


int CvUnit::getSubUnitsAlive() const
{
	return getSubUnitsAlive( getDamage());
}


int CvUnit::getSubUnitsAlive(int iDamage) const
{
	if (iDamage >= maxHitPoints())
	{
		return 0;
	}
	else
	{

//FfH: Added by Kael 10/26/2007
        if (getGroupSize() != 0)
        {
            return getGroupSize();
        }
//FfH: End Add

		return std::max(1, (((m_pUnitInfo->getGroupSize() * (maxHitPoints() - iDamage)) + (maxHitPoints() / ((m_pUnitInfo->getGroupSize() * 2) + 1))) / maxHitPoints()));
	}
}
// returns true if unit can initiate a war action with plot (possibly by declaring war)
bool CvUnit::potentialWarAction(const CvPlot* pPlot) const
{
	TeamTypes ePlotTeam = pPlot->getTeam();
	TeamTypes eUnitTeam = getTeam();

	if (ePlotTeam == NO_TEAM)
	{
		return false;
	}

	if (isEnemy(ePlotTeam, pPlot))
	{
		return true;
	}

	if (getGroup()->AI_isDeclareWar(pPlot) && GET_TEAM(eUnitTeam).AI_getWarPlan(ePlotTeam) != NO_WARPLAN)
	{
		return true;
	}

	return false;
}

//FfH Spell System: Added by Kael 07/23/2007
bool CvUnit::canCast(int spell, bool bTestVisible) //can't be const b/c the python could change stuff
{
    SpellTypes eSpell = (SpellTypes)spell;
    CvPlot* pPlot = plot();
    CvUnit* pLoopUnit;
	if (getImmobileTimer() > 0)
	{
		return false;
	}
    if (!isHuman())
    {
        if (!GC.getSpellInfo(eSpell).isAllowAI())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getPromotionPrereq1() != NO_PROMOTION)
    {
        if (!isHasPromotion((PromotionTypes)GC.getSpellInfo(eSpell).getPromotionPrereq1()))
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getPromotionPrereq2() != NO_PROMOTION)
    {
        if (!isHasPromotion((PromotionTypes)GC.getSpellInfo(eSpell).getPromotionPrereq2()))
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getUnitPrereq() != NO_UNIT)
    {
        if (getUnitType() != (UnitTypes)GC.getSpellInfo(eSpell).getUnitPrereq())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getUnitCombatPrereq() != NO_UNITCOMBAT)
    {
        if (getUnitCombatType() != (UnitCombatTypes)GC.getSpellInfo(eSpell).getUnitCombatPrereq())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getUnitClassPrereq() != NO_UNITCLASS)
    {
        if (getUnitClassType() != (UnitClassTypes)GC.getSpellInfo(eSpell).getUnitClassPrereq())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getCivilizationPrereq() != NO_CIVILIZATION)
    {
        if (getCivilizationType() != (CivilizationTypes)GC.getSpellInfo(eSpell).getCivilizationPrereq())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getReligionPrereq() != NO_RELIGION)
    {
        if (getReligion() != (ReligionTypes)GC.getSpellInfo(eSpell).getReligionPrereq())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getStateReligionPrereq() != NO_RELIGION)
    {
        if (GET_PLAYER(getOwnerINLINE()).getStateReligion() != (ReligionTypes)GC.getSpellInfo(eSpell).getStateReligionPrereq())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getTechPrereq() != NO_TECH)
    {
        if (!GET_TEAM(getTeam()).isHasTech((TechTypes)GC.getSpellInfo(eSpell).getTechPrereq()))
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getConvertUnitType() != NO_UNIT)
    {
        if (getUnitType() == (UnitTypes)GC.getSpellInfo(eSpell).getConvertUnitType())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).isGlobal())
    {
        if (GET_PLAYER(getOwnerINLINE()).isFeatAccomplished(FEAT_GLOBAL_SPELL))
        {
            return false;
        }
    }
    if (GC.getUnitInfo((UnitTypes)getUnitType()).getEquipmentPromotion() != NO_PROMOTION)
    {
        if (GC.getSpellInfo(eSpell).getUnitPrereq() != getUnitType())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getUnitInStackPrereq() != NO_UNIT)
    {
        if (getUnitType() == GC.getSpellInfo(eSpell).getUnitInStackPrereq())
        {
            return false;
        }
        CLLNode<IDInfo>* pUnitNode;
        bool bValid = false;
        pUnitNode = pPlot->headUnitNode();
        while (pUnitNode != NULL)
        {
            pLoopUnit = ::getUnit(pUnitNode->m_data);
            pUnitNode = pPlot->nextUnitNode(pUnitNode);
            if (pLoopUnit->getUnitType() == (UnitTypes)GC.getSpellInfo(eSpell).getUnitInStackPrereq())
            {
                if (getOwner() == pLoopUnit->getOwner())
                {
                    bValid = true;
                }
            }
        }
        if (bValid == false)
        {
            return false;
        }
    }
    if (bTestVisible)
    {
        if (GC.getSpellInfo(eSpell).isDisplayWhenDisabled())
        {
            return true;
        }
    }
    if (!GC.getSpellInfo(eSpell).isIgnoreHasCasted())
    {
        if (isHasCasted())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).isAdjacentToWaterOnly())
    {
        if (!pPlot->isAdjacentToWater())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).isInBordersOnly())
    {
        if (pPlot->getOwner() != getOwner())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).isInCityOnly())
    {
        if (!pPlot->isCity())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getChangePopulation() != 0)
    {
        if (!pPlot->isCity())
        {
            return false;
        }
        if (pPlot->getPlotCity()->getPopulation() <= (-1 * GC.getSpellInfo(eSpell).getChangePopulation()))
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getCost() != 0)
    {
        if (GET_PLAYER(getOwnerINLINE()).getGold() < GC.getSpellInfo(eSpell).getCost())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).isRemoveHasCasted())
    {
        if (!isHasCasted())
        {
            return false;
        }
    }
    if (GC.getSpellInfo(eSpell).getCreateUnitType() != NO_UNIT)
    {
        if (getDuration() > 0) // to prevent summons summoning spinlocks
        {
            return false;
        }
        if (GC.getSpellInfo(eSpell).isPermanentUnitCreate())
        {
            int iCount = 0;
            int iLoop = 0;
            CvPlayer& kPlayer = GET_PLAYER(getOwnerINLINE());
            for (pLoopUnit = kPlayer.firstUnit(&iLoop); pLoopUnit != NULL; pLoopUnit = kPlayer.nextUnit(&iLoop))
            {
                if ((GC.getSpellInfo(eSpell).getPromotionPrereq1() == NO_PROMOTION ||
                  pLoopUnit->isHasPromotion((PromotionTypes)GC.getSpellInfo(eSpell).getPromotionPrereq1())) &&
                  (GC.getSpellInfo(eSpell).getPromotionPrereq2() == NO_PROMOTION ||
                  pLoopUnit->isHasPromotion((PromotionTypes)GC.getSpellInfo(eSpell).getPromotionPrereq2())))
                {
                    iCount += 1;
                }
            }
            if (iCount <= kPlayer.getUnitClassCount((UnitClassTypes)GC.getUnitInfo((UnitTypes)GC.getSpellInfo(eSpell).getCreateUnitType()).getUnitClassType()))
            {
                return false;
            }
        }
    }
    if (!isEmpty(GC.getSpellInfo(eSpell).getPyRequirement()))
    {
        CyUnit* pyUnit = new CyUnit(this);
        CyArgsList argsList;
        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
        argsList.add(spell);//the spell #
        long lResult=0;
        gDLL->getPythonIFace()->callFunction(PYSpellModule, "canCast", argsList.makeFunctionArgs(), &lResult);
        delete pyUnit; // python fxn must not hold on to this pointer
        if (lResult == 0)
        {
            return false;
        }
        return true;
    }
    if (GC.getSpellInfo(eSpell).isRemoveHasCasted())
    {
        if (isHasCasted())
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getAddPromotionType1() != NO_PROMOTION)
    {
        if (canAddPromotion(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getRemovePromotionType1() != NO_PROMOTION)
    {
        if (canRemovePromotion(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getConvertUnitType() != NO_UNIT)
    {
        return true;
    }
    if (GC.getSpellInfo(eSpell).getCreateBuildingType() != NO_BUILDING)
    {
        if (canCreateBuilding(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getCreateFeatureType() != NO_FEATURE)
    {
        if (canCreateFeature(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getCreateImprovementType() != NO_IMPROVEMENT)
    {
        if (canCreateImprovement(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getSpreadReligion() != NO_RELIGION)
    {
        if (canSpreadReligion(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getCreateUnitType() != NO_UNIT)
    {
        return true;
    }
    if (GC.getSpellInfo(eSpell).getDamage() != 0)
    {
        return true;
    }
    if (GC.getSpellInfo(eSpell).isDispel())
    {
        if (canDispel(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getImmobileTurns() > 0)
    {
        if (canImmobile(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).isPush())
    {
        if (canPush(spell))
        {
            return true;
        }
    }
    if (GC.getSpellInfo(eSpell).getChangePopulation() > 0)
    {
        return true;
    }
    if (!isEmpty(GC.getSpellInfo(eSpell).getPyResult()))
    {
        return true;
    }
    return false;
}

bool CvUnit::canAddPromotion(int spell)
{
   	PromotionTypes ePromotion1 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getAddPromotionType1();
   	PromotionTypes ePromotion2 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getAddPromotionType2();
   	PromotionTypes ePromotion3 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getAddPromotionType3();
    if (GC.getSpellInfo((SpellTypes)spell).isBuffCasterOnly())
    {
        if (ePromotion1 != NO_PROMOTION)
        {
            if (!isHasPromotion(ePromotion1))
            {
                return true;
            }
        }
        if (ePromotion2 != NO_PROMOTION)
        {
            if (!isHasPromotion(ePromotion2))
            {
                return true;
            }
        }
        if (ePromotion3 != NO_PROMOTION)
        {
            if (!isHasPromotion(ePromotion3))
            {
                return true;
            }
        }
        return false;
    }
	CvUnit* pLoopUnit;
    CvPlot* pLoopPlot;
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                    if (!pLoopUnit->isImmuneToSpell(this, spell))
                    {
                        if (ePromotion1 != NO_PROMOTION)
                        {
                            if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                            {
                                if (GC.getPromotionInfo(ePromotion1).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                {
                                    if (!pLoopUnit->isHasPromotion(ePromotion1))
                                    {
                                        return true;
                                    }
                                }
                            }
                        }
                        if (ePromotion2 != NO_PROMOTION)
                        {
                            if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                            {
                                if (GC.getPromotionInfo(ePromotion2).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                {
                                    if (!pLoopUnit->isHasPromotion(ePromotion2))
                                    {
                                        return true;
                                    }
                                }
                            }
                        }
                        if (ePromotion3 != NO_PROMOTION)
                        {
                            if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                            {
                                if (GC.getPromotionInfo(ePromotion3).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                {
                                    if (!pLoopUnit->isHasPromotion(ePromotion3))
                                    {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
		}
	}
	return false;
}

bool CvUnit::canCreateBuilding(int spell)
{
    if (!plot()->isCity())
    {
        return false;
    }
    if (plot()->getPlotCity()->getNumBuilding((BuildingTypes)GC.getSpellInfo((SpellTypes)spell).getCreateBuildingType()) > 0)
    {
        return false;
    }
    return true;
}

bool CvUnit::canCreateFeature(int spell)
{
    if (plot()->isCity())
    {
        return false;
    }
    if (!plot()->canHaveFeature((FeatureTypes)GC.getSpellInfo((SpellTypes)spell).getCreateFeatureType()))
    {
        return false;
    }
    if (plot()->getFeatureType() != NO_FEATURE)
    {
        return false;
    }
    if (plot()->getImprovementType() != NO_IMPROVEMENT)
    {
        if (!GC.getCivilizationInfo(getCivilizationType()).isMaintainFeatures(GC.getSpellInfo((SpellTypes)spell).getCreateFeatureType()))
        {
            return false;
        }
    }
    return true;
}

bool CvUnit::canCreateImprovement(int spell)
{
    if (plot()->isCity())
    {
        return false;
    }
    if (!plot()->canHaveImprovement((ImprovementTypes)GC.getSpellInfo((SpellTypes)spell).getCreateImprovementType()))
    {
        return false;
    }
    if (plot()->getImprovementType() != NO_IMPROVEMENT)
    {
        return false;
    }
    return true;
}

bool CvUnit::canDispel(int spell)
{
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                pUnitNode = pLoopPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                    if (!pLoopUnit->isImmuneToSpell(this, spell))
                    {
                        for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
                        {
                            if (pLoopUnit->isHasPromotion((PromotionTypes)iI))
                            {
                                if (GC.getPromotionInfo((PromotionTypes)iI).isDispellable())
                                {
                                    if ((GC.getPromotionInfo((PromotionTypes)iI).getAIWeight() < 0 && pLoopUnit->getTeam() == getTeam())
                                    || (GC.getPromotionInfo((PromotionTypes)iI).getAIWeight() > 0 && pLoopUnit->isEnemy(getTeam())))
                                    {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return false;
}

bool CvUnit::canImmobile(int spell)
{
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                pUnitNode = pLoopPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                    if (!pLoopUnit->isImmuneToSpell(this, spell))
                    {
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

bool CvUnit::canPush(int spell)
{
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                if (!pLoopPlot->isCity())
                {
                    pUnitNode = pLoopPlot->headUnitNode();
                    while (pUnitNode != NULL)
                    {
                        pLoopUnit = ::getUnit(pUnitNode->m_data);
                        pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                        if (!pLoopUnit->isImmuneToSpell(this, spell))
                        {
                            return true;
                        }
                    }
                }
            }
        }
    }
    return false;
}

bool CvUnit::canRemovePromotion(int spell)
{
   	PromotionTypes ePromotion1 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType1();
   	PromotionTypes ePromotion2 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType2();
   	PromotionTypes ePromotion3 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType3();
    if (GC.getSpellInfo((SpellTypes)spell).isBuffCasterOnly())
    {
        if (ePromotion1 != NO_PROMOTION)
        {
            if (isHasPromotion(ePromotion1))
            {
                return true;
            }
        }
        if (ePromotion2 != NO_PROMOTION)
        {
            if (isHasPromotion(ePromotion2))
            {
                return true;
            }
        }
        if (ePromotion3 != NO_PROMOTION)
        {
            if (isHasPromotion(ePromotion3))
            {
                return true;
            }
        }
        return false;
    }
	CvUnit* pLoopUnit;
    CvPlot* pLoopPlot;
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                CLLNode<IDInfo>* pUnitNode = pLoopPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                    if (!pLoopUnit->isImmuneToSpell(this, spell))
                    {
                        if (ePromotion1 != NO_PROMOTION)
                        {
                            if (pLoopUnit->isHasPromotion(ePromotion1))
                            {
                                return true;
                            }
                        }
                        if (ePromotion2 != NO_PROMOTION)
                        {
                            if (pLoopUnit->isHasPromotion(ePromotion2))
                            {
                                return true;
                            }
                        }
                        if (ePromotion3 != NO_PROMOTION)
                        {
                            if (pLoopUnit->isHasPromotion(ePromotion3))
                            {
                                return true;
                            }
                        }
                    }
                }
            }
		}
	}
	return false;
}

bool CvUnit::canSpreadReligion(int spell)
{
   	ReligionTypes eReligion = (ReligionTypes)GC.getSpellInfo((SpellTypes)spell).getSpreadReligion();
	if (eReligion == NO_RELIGION)
	{
		return false;
	}
	CvCity* pCity = plot()->getPlotCity();
	if (pCity == NULL)
	{
		return false;
	}
	if (pCity->isHasReligion(eReligion))
	{
		return false;
	}
	return true;
}

void CvUnit::cast(int spell)
{
    if (GC.getSpellInfo((SpellTypes)spell).isHasCasted())
    {
        setHasCasted(true);
    }
    for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
    {
        if (isHasPromotion((PromotionTypes)iI))
        {
            if (GC.getPromotionInfo((PromotionTypes)iI).isRemovedByCasting())
            {
                setHasPromotion((PromotionTypes)iI, false);
            }
        }
    }
    if (GC.getSpellInfo((SpellTypes)spell).isGlobal())
    {
        GET_PLAYER(getOwnerINLINE()).setFeatAccomplished(FEAT_GLOBAL_SPELL, true);
		for (int iPlayer = 0; iPlayer < MAX_CIV_PLAYERS; ++iPlayer)
		{
		    if (GET_PLAYER((PlayerTypes)iPlayer).isAlive())
		    {
                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)iPlayer, false, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_GLOBAL_SPELL", GC.getSpellInfo((SpellTypes)spell).getDescription()), "AS2D_CIVIC_ADOPT", MESSAGE_TYPE_MINOR_EVENT);
		    }
		}
    }
    int iMiscastChance = GC.getSpellInfo((SpellTypes)spell).getMiscastChance() + m_pUnitInfo->getMiscastChance();
    if (iMiscastChance > 0)
    {
        if (GC.getGameINLINE().getSorenRandNum(100, "Miscast") < iMiscastChance)
        {
            if (!isEmpty(GC.getSpellInfo((SpellTypes)spell).getPyMiscast()))
            {
                CyUnit* pyUnit = new CyUnit(this);
                CyArgsList argsList;
                argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
                argsList.add(spell);//the spell #
                gDLL->getPythonIFace()->callFunction(PYSpellModule, "miscast", argsList.makeFunctionArgs()); //, &lResult
                delete pyUnit; // python fxn must not hold on to this pointer
            }
        }
        gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_MISCAST"), "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, "art/interface/buttons/spells/miscast.dds", (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"), getX_INLINE(), getY_INLINE(), true, true);
        gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
        return;
    }
    if (GC.getSpellInfo((SpellTypes)spell).getDelay() > 0)
    {
        if (getDelayedSpell() == NO_SPELL)
        {
            changeImmobileTimer(GC.getSpellInfo((SpellTypes)spell).getDelay());
            setDelayedSpell(spell);
            gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
            gDLL->getInterfaceIFace()->changeCycleSelectionCounter((GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_QUICK_MOVES)) ? 1 : 2);
            return;
        }
        setDelayedSpell(NO_SPELL);
    }
    if (GC.getSpellInfo((SpellTypes)spell).getCreateUnitType() != -1)
    {
        int iUnitNum = GC.getSpellInfo((SpellTypes)spell).getCreateUnitNum();
        if (isTwincast())
        {
            iUnitNum *= 2;
        }
        for (int i=0; i < iUnitNum; ++i)
        {
            castCreateUnit(spell);
        }
    }
    if (GC.getSpellInfo((SpellTypes)spell).getAddPromotionType1() != -1)
    {
        castAddPromotion(spell);
    }
    if (GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType1() != -1)
    {
        castRemovePromotion(spell);
    }
    if (GC.getSpellInfo((SpellTypes)spell).getConvertUnitType() != NO_UNIT)
    {
        castConvertUnit(spell);
    }
    if (GC.getSpellInfo((SpellTypes)spell).getCreateBuildingType() != NO_BUILDING)
    {
        if (canCreateBuilding(spell))
        {
            plot()->getPlotCity()->setNumRealBuilding((BuildingTypes)GC.getSpellInfo((SpellTypes)spell).getCreateBuildingType(), true);
        }
    }
    if (GC.getSpellInfo((SpellTypes)spell).getCreateFeatureType() != NO_FEATURE)
    {
        if (canCreateFeature(spell))
        {
            plot()->setFeatureType((FeatureTypes)GC.getSpellInfo((SpellTypes)spell).getCreateFeatureType(), -1);
        }
    }
    if (GC.getSpellInfo((SpellTypes)spell).getCreateImprovementType() != NO_IMPROVEMENT)
    {
        if (canCreateImprovement(spell))
        {
            plot()->setImprovementType((ImprovementTypes)GC.getSpellInfo((SpellTypes)spell).getCreateImprovementType());
        }
    }
    if (GC.getSpellInfo((SpellTypes)spell).getSpreadReligion() != NO_RELIGION)
    {
        if (canSpreadReligion(spell))
        {
            plot()->getPlotCity()->setHasReligion((ReligionTypes)GC.getSpellInfo((SpellTypes)spell).getSpreadReligion(), true, true, true);
        }
    }
    if (GC.getSpellInfo((SpellTypes)spell).getDamage() != 0)
    {
        castDamage(spell);
    }
    if (GC.getSpellInfo((SpellTypes)spell).getImmobileTurns() != 0)
    {
        castImmobile(spell);
    }
    if (GC.getSpellInfo((SpellTypes)spell).isPush())
    {
        castPush(spell);
    }
    if (GC.getSpellInfo((SpellTypes)spell).isRemoveHasCasted())
    {
        setHasCasted(false);
    }
    if (GC.getSpellInfo((SpellTypes)spell).getCost() != 0)
    {
        GET_PLAYER(getOwnerINLINE()).changeGold(-1 * GC.getSpellInfo((SpellTypes)spell).getCost());
    }
    if (GC.getSpellInfo((SpellTypes)spell).getChangePopulation() != 0)
    {
        plot()->getPlotCity()->changePopulation(GC.getSpellInfo((SpellTypes)spell).getChangePopulation());
    }
    if (!isEmpty(GC.getSpellInfo((SpellTypes)spell).getPyResult()))
    {
        CyUnit* pyUnit = new CyUnit(this);
        CyArgsList argsList;
        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyUnit));	// pass in unit class
        argsList.add(spell);//the spell #
        gDLL->getPythonIFace()->callFunction(PYSpellModule, "cast", argsList.makeFunctionArgs()); //, &lResult
        delete pyUnit; // python fxn must not hold on to this pointer
    }
    if (plot()->isVisibleToWatchingHuman())
    {
        if (GC.getSpellInfo((SpellTypes)spell).getEffect() != -1)
        {
            gDLL->getEngineIFace()->TriggerEffect(GC.getSpellInfo((SpellTypes)spell).getEffect(), plot()->getPoint(), (float)(GC.getASyncRand().get(360)));
        }
        if (GC.getSpellInfo((SpellTypes)spell).getSound() != NULL)
        {
            gDLL->getInterfaceIFace()->playGeneralSound(GC.getSpellInfo((SpellTypes)spell).getSound(), plot()->getPoint());
        }
        gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), true, GC.getEVENT_MESSAGE_TIME(), GC.getSpellInfo((SpellTypes)spell).getDescription(), "AS2D_WONDER_UNIT_BUILD", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"), getX_INLINE(), getY_INLINE(), true, true);
    }
    gDLL->getInterfaceIFace()->setDirty(SelectionButtons_DIRTY_BIT, true);
    if (GC.getSpellInfo((SpellTypes)spell).isSacrificeCaster())
    {
        kill(true);
    }
}

void CvUnit::castAddPromotion(int spell)
{
   	PromotionTypes ePromotion1 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getAddPromotionType1();
   	PromotionTypes ePromotion2 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getAddPromotionType2();
   	PromotionTypes ePromotion3 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getAddPromotionType3();
    if (GC.getSpellInfo((SpellTypes)spell).isBuffCasterOnly())
    {
        if (ePromotion1 != NO_PROMOTION)
        {
            setHasPromotion(ePromotion1, true);
        }
        if (ePromotion2 != NO_PROMOTION)
        {
            setHasPromotion(ePromotion2, true);
        }
        if (ePromotion3 != NO_PROMOTION)
        {
            setHasPromotion(ePromotion3, true);
        }
    }
    else
    {
        int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
        bool bResistable = GC.getSpellInfo((SpellTypes)spell).isResistable();
        CLLNode<IDInfo>* pUnitNode;
        CvUnit* pLoopUnit;
        CvPlot* pLoopPlot;
        for (int i = -iRange; i <= iRange; ++i)
        {
            for (int j = -iRange; j <= iRange; ++j)
            {
                pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
                if (NULL != pLoopPlot)
                {
                    pUnitNode = pLoopPlot->headUnitNode();
                    while (pUnitNode != NULL)
                    {
                        pLoopUnit = ::getUnit(pUnitNode->m_data);
                        pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                        if (!pLoopUnit->isImmuneToSpell(this, spell))
                        {
                            if (bResistable)
                            {
                                if (!pLoopUnit->isResisted(this, spell))
                                {
                                    if (ePromotion1 != NO_PROMOTION)
                                    {
                                        if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                                        {
                                            if (GC.getPromotionInfo(ePromotion1).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                            {
                                                pLoopUnit->setHasPromotion(ePromotion1, true);
                                            }
                                        }
                                    }
                                    if (ePromotion2 != NO_PROMOTION)
                                    {
                                        if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                                        {
                                            if (GC.getPromotionInfo(ePromotion2).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                            {
                                                pLoopUnit->setHasPromotion(ePromotion2, true);
                                            }
                                        }
                                    }
                                    if (ePromotion3 != NO_PROMOTION)
                                    {
                                        if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                                        {
                                            if (GC.getPromotionInfo(ePromotion3).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                            {
                                                pLoopUnit->setHasPromotion(ePromotion3, true);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                if (ePromotion1 != NO_PROMOTION)
                                {
                                    if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                                    {
                                        if (GC.getPromotionInfo(ePromotion1).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                        {
                                            pLoopUnit->setHasPromotion(ePromotion1, true);
                                        }
                                    }
                                }
                                if (ePromotion2 != NO_PROMOTION)
                                {
                                    if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                                    {
                                        if (GC.getPromotionInfo(ePromotion2).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                        {
                                            pLoopUnit->setHasPromotion(ePromotion2, true);
                                        }
                                    }
                                }
                                if (ePromotion3 != NO_PROMOTION)
                                {
                                    if (pLoopUnit->getUnitCombatType() != NO_UNITCOMBAT)
                                    {
                                        if (GC.getPromotionInfo(ePromotion3).getUnitCombat(pLoopUnit->getUnitCombatType()))
                                        {
                                            pLoopUnit->setHasPromotion(ePromotion3, true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::castDamage(int spell)
{
    bool bResistable = GC.getSpellInfo((SpellTypes)spell).isResistable();
    int iDmg = GC.getSpellInfo((SpellTypes)spell).getDamage();
    int iDmgLimit = GC.getSpellInfo((SpellTypes)spell).getDamageLimit();
    int iDmgType = GC.getSpellInfo((SpellTypes)spell).getDamageType();
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                if (pLoopPlot->getX() != plot()->getX() || pLoopPlot->getY() != plot()->getY())
                {
                    pUnitNode = pLoopPlot->headUnitNode();
                    while (pUnitNode != NULL)
                    {
                        pLoopUnit = ::getUnit(pUnitNode->m_data);
                        pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                        if (!pLoopUnit->isImmuneToSpell(this, spell))
                        {
                            if (bResistable)
                            {
                                if (!pLoopUnit->isResisted(this, spell))
                                {
                                    pLoopUnit->doDamage((iDmg / 2) + GC.getGameINLINE().getSorenRandNum(iDmg, "doDamage"), iDmgLimit, this, iDmgType, true);
                                }
                            }
                            else
                            {
                                pLoopUnit->doDamage((iDmg / 2) + GC.getGameINLINE().getSorenRandNum(iDmg, "doDamage"), iDmgLimit, this, iDmgType, true);
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::castDispel(int spell)
{
    bool bResistable = GC.getSpellInfo((SpellTypes)spell).isResistable();
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                pUnitNode = pLoopPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                    if (!pLoopUnit->isImmuneToSpell(this, spell))
                    {
                        if (pLoopUnit->isEnemy(getTeam()))
                        {
                            if (bResistable)
                            {
                                if (pLoopUnit->isResisted(this, spell))
                                {
                                    continue;
                                }
                            }
                            for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
                            {
                                if (GC.getPromotionInfo((PromotionTypes)iI).isDispellable() && GC.getPromotionInfo((PromotionTypes)iI).getAIWeight() > 0)
                                {
                                    setHasPromotion((PromotionTypes)iI, false);
                                }
                            }
                        }
                        else
                        {
                            for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
                            {
                                if (GC.getPromotionInfo((PromotionTypes)iI).isDispellable() && GC.getPromotionInfo((PromotionTypes)iI).getAIWeight() < 0)
                                {
                                    setHasPromotion((PromotionTypes)iI, false);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::castImmobile(int spell)
{
    bool bResistable = GC.getSpellInfo((SpellTypes)spell).isResistable();
    int iImmobileTurns = GC.getSpellInfo((SpellTypes)spell).getImmobileTurns();
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                if (pLoopPlot->getX() != plot()->getX() || pLoopPlot->getY() != plot()->getY())
                {
                    pUnitNode = pLoopPlot->headUnitNode();
                    while (pUnitNode != NULL)
                    {
                        pLoopUnit = ::getUnit(pUnitNode->m_data);
                        pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                        if (!pLoopUnit->isImmuneToSpell(this, spell) && pLoopUnit->getImmobileTimer() == 0)
                        {
                            if (bResistable)
                            {
                                if (!pLoopUnit->isResisted(this, spell))
                                {
                                    pLoopUnit->changeImmobileTimer(iImmobileTurns);
                                    gDLL->getInterfaceIFace()->addMessage((PlayerTypes)pLoopUnit->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_IMMOBILE"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                                    gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_IMMOBILE"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                                }
                            }
                            else
                            {
                                pLoopUnit->changeImmobileTimer(iImmobileTurns);
                                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)pLoopUnit->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_IMMOBILE"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_IMMOBILE"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::castPush(int spell)
{
    bool bResistable = GC.getSpellInfo((SpellTypes)spell).isResistable();
    int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvPlot* pLoopPlot;
	CvPlot* pPushPlot;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            int iPushY = plot()->getY_INLINE() + (i*2);
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            pPushPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i*2, j*2);
            if (!pLoopPlot->isCity())
            {
                if (NULL != pLoopPlot)
                {
                    if (NULL != pPushPlot)
                    {
                        if (pLoopPlot->getX() != plot()->getX() || pLoopPlot->getY() != plot()->getY())
                        {
                            pUnitNode = pLoopPlot->headUnitNode();
                            while (pUnitNode != NULL)
                            {
                                pLoopUnit = ::getUnit(pUnitNode->m_data);
                                pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                                if (pLoopUnit->canMoveInto(pPushPlot, false, false, false))
                                {
                                    if (!pLoopUnit->isImmuneToSpell(this, spell))
                                    {
                                        if (bResistable)
                                        {
                                            if (!pLoopUnit->isResisted(this, spell))
                                            {
                                                pLoopUnit->setXY(pPushPlot->getX(),pPushPlot->getY(),false,true,true);
                                                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)pLoopUnit->getOwner(), false, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_PUSH"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                                                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), false, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_PUSH"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                                            }
                                        }
                                        else
                                        {
                                            pLoopUnit->setXY(pPushPlot->getX(),pPushPlot->getY(),false,true,true);
                                            gDLL->getInterfaceIFace()->addMessage((PlayerTypes)pLoopUnit->getOwner(), false, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_PUSH"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                                            gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), false, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_PUSH"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, GC.getSpellInfo((SpellTypes)spell).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::castRemovePromotion(int spell)
{
   	PromotionTypes ePromotion1 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType1();
   	PromotionTypes ePromotion2 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType2();
   	PromotionTypes ePromotion3 = (PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getRemovePromotionType3();
    if (GC.getSpellInfo((SpellTypes)spell).isBuffCasterOnly())
    {
        if (ePromotion1 != NO_PROMOTION)
        {
            setHasPromotion(ePromotion1, false);
        }
        if (ePromotion2 != NO_PROMOTION)
        {
            setHasPromotion(ePromotion2, false);
        }
        if (ePromotion3 != NO_PROMOTION)
        {
            setHasPromotion(ePromotion3, false);
        }
    }
    else
    {
        int iRange = GC.getSpellInfo((SpellTypes)spell).getRange();
        bool bResistable = GC.getSpellInfo((SpellTypes)spell).isResistable();
        CLLNode<IDInfo>* pUnitNode;
        CvUnit* pLoopUnit;
        CvPlot* pLoopPlot;
        for (int i = -iRange; i <= iRange; ++i)
        {
            for (int j = -iRange; j <= iRange; ++j)
            {
                pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
                if (NULL != pLoopPlot)
                {
                    pUnitNode = pLoopPlot->headUnitNode();
                    while (pUnitNode != NULL)
                    {
                        pLoopUnit = ::getUnit(pUnitNode->m_data);
                        pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                        if (!pLoopUnit->isImmuneToSpell(this, spell))
                        {
                            if (bResistable)
                            {
                                if (!pLoopUnit->isResisted(this, spell))
                                {
                                    if (ePromotion1 != NO_PROMOTION)
                                    {
                                        pLoopUnit->setHasPromotion(ePromotion1, false);
                                    }
                                    if (ePromotion2 != NO_PROMOTION)
                                    {
                                        pLoopUnit->setHasPromotion(ePromotion2, false);
                                    }
                                    if (ePromotion3 != NO_PROMOTION)
                                    {
                                        pLoopUnit->setHasPromotion(ePromotion3, false);
                                    }
                                }
                            }
                            else
                            {
                                if (ePromotion1 != NO_PROMOTION)
                                {
                                    pLoopUnit->setHasPromotion(ePromotion1, false);
                                }
                                if (ePromotion2 != NO_PROMOTION)
                                {
                                    pLoopUnit->setHasPromotion(ePromotion2, false);
                                }
                                if (ePromotion3 != NO_PROMOTION)
                                {
                                    pLoopUnit->setHasPromotion(ePromotion3, false);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::castConvertUnit(int spell)
{
	CvUnit* pUnit;
   	pUnit = GET_PLAYER(getOwnerINLINE()).initUnit((UnitTypes)GC.getSpellInfo((SpellTypes)spell).getConvertUnitType(), getX_INLINE(), getY_INLINE(), AI_getUnitAIType());
   	pUnit->convert(this);
}

void CvUnit::castCreateUnit(int spell)
{
    int iI;
	CvUnit* pUnit;
   	pUnit = GET_PLAYER(getOwnerINLINE()).initUnit((UnitTypes)GC.getSpellInfo((SpellTypes)spell).getCreateUnitType(), getX_INLINE(), getY_INLINE(), AI_getUnitAIType());
   	if (GC.getSpellInfo((SpellTypes)spell).isPermanentUnitCreate())
   	{
        pUnit->changeImmobileTimer(2);
   	}
   	else
   	{
        pUnit->changeDuration(2);
        if (pUnit->getSpecialUnitType() != GC.getDefineINT("SPECIALUNIT_SPELL"))
   	    {
            pUnit->changeDuration(GET_PLAYER(getOwnerINLINE()).getSummonDuration());
   	    }
   	}
	for (iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
	    if (isHasPromotion((PromotionTypes)iI))
	    {
	        if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk() != NO_PROMOTION)
	        {
	            pUnit->setHasPromotion((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk(), true);
	        }
	    }
	}
   	if (GC.getSpellInfo((SpellTypes)spell).getCreateUnitPromotion() != NO_PROMOTION)
   	{
        pUnit->setHasPromotion((PromotionTypes)GC.getSpellInfo((SpellTypes)spell).getCreateUnitPromotion(), true);
   	}
   	if (isHiddenNationality())
   	{
        pUnit->setHasPromotion((PromotionTypes)GC.getDefineINT("HIDDEN_NATIONALITY_PROMOTION"), true);
   	}
   	pUnit->doTurn();
   	if (!isHuman())
   	{
        pUnit->AI_update();
   	}
}

bool CvUnit::isHasCasted() const
{
	return m_bHasCasted;
}

void CvUnit::setHasCasted(bool bNewValue)
{
	m_bHasCasted = bNewValue;
}

void CvUnit::setIgnoreBuildingDefense(bool bNewValue)
{
	m_bIgnoreBuildingDefense = bNewValue;
}

bool CvUnit::isImmortal() const
{
	return m_bImmortal;
}

void CvUnit::setImmortal(bool bNewValue)
{
	m_bImmortal = bNewValue;
}

bool CvUnit::isImmuneToSpell(CvUnit* pCaster, int spell)
{
    if (isImmuneToMagic())
    {
        return true;
    }
   	if (GC.getSpellInfo((SpellTypes)spell).isImmuneTeam())
   	{
   	    if (getTeam() == pCaster->getTeam())
   	    {
   	        return true;
   	    }
   	}
   	if (GC.getSpellInfo((SpellTypes)spell).isImmuneNeutral())
   	{
   	    if (getTeam() != pCaster->getTeam())
   	    {
   	        if (!isEnemy(pCaster->getTeam()))
            {
                return true;
            }
        }
   	}
   	if (GC.getSpellInfo((SpellTypes)spell).isImmuneEnemy())
   	{
        if (isEnemy(pCaster->getTeam()))
        {
            return true;
        }
   	}
   	if (GC.getSpellInfo((SpellTypes)spell).isImmuneFlying())
   	{
   	    if (isFlying())
   	    {
   	        return true;
   	    }
   	}
   	if (GC.getSpellInfo((SpellTypes)spell).isImmuneNotAlive())
   	{
   	    if (!isAlive())
   	    {
   	        return true;
   	    }
   	}
    return false;
}

int CvUnit::getDelayedSpell() const
{
	return m_iDelayedSpell;
}

void CvUnit::setDelayedSpell(int iNewValue)
{
	m_iDelayedSpell = iNewValue;
}

int CvUnit::getDuration() const
{
	return m_iDuration;
}

void CvUnit::setDuration(int iNewValue)
{
	m_iDuration = iNewValue;
}

void CvUnit::changeDuration(int iChange)
{
	setDuration(getDuration() + iChange);
}

bool CvUnit::isAlive() const
{
	return m_bAlive;
}

void CvUnit::setAlive(bool bNewValue)
{
    m_bAlive = bNewValue;
}

int CvUnit::getBetterDefenderThanPercent() const
{
	return m_iBetterDefenderThanPercent;
}

void CvUnit::changeBetterDefenderThanPercent(int iChange)
{
	if (iChange != 0)
	{
		m_iBetterDefenderThanPercent = (m_iBetterDefenderThanPercent + iChange);
	}
}

bool CvUnit::isDoubleFortifyBonus() const
{
	return m_bDoubleFortifyBonus;
}

void CvUnit::setDoubleFortifyBonus(bool bNewValue)
{
    m_bDoubleFortifyBonus = bNewValue;
}

void CvUnit::setOnlyDefensive(bool bNewValue)
{
    m_bOnlyDefensive = bNewValue;
}

int CvUnit::getCombatHealPercent() const
{
	return m_iCombatHealPercent;
}

void CvUnit::changeCombatHealPercent(int iChange)
{
	if (iChange != 0)
	{
		m_iCombatHealPercent = (m_iCombatHealPercent + iChange);
	}
}

void CvUnit::calcCombatLimit()
{
    int iBestValue = m_pUnitInfo->getCombatLimit();
    int iValue = 0;
   	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		if (isHasPromotion((PromotionTypes)iI))
		{
		    iValue = GC.getPromotionInfo((PromotionTypes)iI).getCombatLimit();
            if (iValue != 0)
            {
                if (iValue < iBestValue)
                {
                    iBestValue = iValue;
                }
            }
		}
	}
	m_iCombatLimit = iBestValue;
}

int CvUnit::getCombatPercentInBorders() const
{
	return m_iCombatPercentInBorders;
}

void CvUnit::changeCombatPercentInBorders(int iChange)
{
	if (iChange != 0)
	{
		m_iCombatPercentInBorders = (m_iCombatPercentInBorders + iChange);
		setInfoBarDirty(true);
	}
}

int CvUnit::getCombatPercentGlobalCounter() const
{
	return m_iCombatPercentGlobalCounter;
}

void CvUnit::changeCombatPercentGlobalCounter(int iChange)
{
	if (iChange != 0)
	{
		m_iCombatPercentGlobalCounter = (m_iCombatPercentGlobalCounter + iChange);
		setInfoBarDirty(true);
	}
}

bool CvUnit::isBoarding() const
{
	return m_bBoarding;
}

void CvUnit::setBoarding(bool bNewValue)
{
    m_bBoarding = bNewValue;
}

bool CvUnit::isFear() const
{
	return m_bFear;
}

void CvUnit::setFear(bool bNewValue)
{
    m_bFear = bNewValue;
}

bool CvUnit::isFleeImmortal() const
{
	return m_bFleeImmortal;
}

void CvUnit::setFleeImmortal(bool bNewValue)
{
    m_bFleeImmortal = bNewValue;
}

bool CvUnit::isFleeWithdrawl() const
{
	return m_bFleeWithdrawl;
}

void CvUnit::setFleeWithdrawl(bool bNewValue)
{
    m_bFleeWithdrawl = bNewValue;
}

bool CvUnit::isFlying() const
{
	return m_bFlying;
}

void CvUnit::setFlying(bool bNewValue)
{
    m_bFlying = bNewValue;
}

int CvUnit::getFreePromotionPick() const
{
	return m_iFreePromotionPick;
}

void CvUnit::changeFreePromotionPick(int iChange)
{
    if (iChange != 0)
    {
        m_iFreePromotionPick = getFreePromotionPick() + iChange;
    }
}

int CvUnit::getGroupSize() const
{
    if (GC.getGameINLINE().isOption(GAMEOPTION_ADVENTURE_MODE))
    {
        return 1;
    }
	return m_iGroupSize;
}

void CvUnit::setGroupSize(int iNewValue)
{
    m_iGroupSize = iNewValue;
}

bool CvUnit::isHiddenNationality() const
{
    if (isCargo())
    {
        if (!getTransportUnit()->isHiddenNationality())
        {
            return false;
        }
    }
	return m_bHiddenNationality;
}

void CvUnit::setHiddenNationality(bool bNewValue)
{
    if (bNewValue)
    {
        joinGroup(NULL, true);
    }
    m_bHiddenNationality = bNewValue;
}

bool CvUnit::isImmuneToCapture() const
{
	return m_bImmuneToCapture;
}

void CvUnit::setImmuneToCapture(bool bNewValue)
{
    m_bImmuneToCapture = bNewValue;
}

bool CvUnit::isImmuneToFear() const
{
    if(!isAlive())
    {
        return true;
    }
	return m_bImmuneToFear;
}

void CvUnit::setImmuneToFear(bool bNewValue)
{
    m_bImmuneToFear = bNewValue;
}

void CvUnit::setImmuneToMagic(bool bNewValue)
{
    m_bImmuneToMagic = bNewValue;
}

bool CvUnit::isImmuneToMagic() const
{
	return m_bImmuneToMagic;
}

void CvUnit::mutate()
{
    int iMutationChance = GC.getDefineINT("MUTATION_CHANCE");
   	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
		if (GC.getPromotionInfo((PromotionTypes)iI).isMutation())
		{
    		if (GC.getGameINLINE().getSorenRandNum(100, "Mutation") <= iMutationChance)
		    {
                setHasPromotion(((PromotionTypes)iI), true);
		    }
		}
	}
}

bool CvUnit::isTargetWeakestUnit() const
{
	return m_bTargetWeakestUnit;
}

void CvUnit::setTargetWeakestUnit(bool bNewValue)
{
    m_bTargetWeakestUnit = bNewValue;
}

bool CvUnit::isTargetWeakestUnitCounter() const
{
	return m_bTargetWeakestUnitCounter;
}

void CvUnit::setTargetWeakestUnitCounter(bool bNewValue)
{
    m_bTargetWeakestUnitCounter = bNewValue;
}

bool CvUnit::isTwincast() const
{
	return m_bTwincast;
}

void CvUnit::setTwincast(bool bNewValue)
{
    m_bTwincast = bNewValue;
}

bool CvUnit::isWaterWalking() const
{
	return m_bWaterWalking;
}

void CvUnit::setWaterWalking(bool bNewValue)
{
    m_bWaterWalking = bNewValue;
}

int CvUnit::getWithdrawlProbDefensive() const
{
	return std::max(0, (m_pUnitInfo->getWithdrawlProbDefensive() + getExtraWithdrawal()));
}

void CvUnit::setInvisibleType(int iNewValue)
{
    m_iInvisibleType = iNewValue;
}

int CvUnit::getRace() const
{
	return m_iRace;
}

void CvUnit::setRace(int iNewValue)
{
    if (m_iRace != NO_PROMOTION)
    {
        setHasPromotion((PromotionTypes)m_iRace, false);
    }
	m_iRace = iNewValue;
}

int CvUnit::getReligion() const
{
	return m_iReligion;
}

void CvUnit::setReligion(int iReligion)
{
	m_iReligion = iReligion;
}

int CvUnit::getResist() const
{
	return m_iResist;
}

void CvUnit::setResist(int iNewValue)
{
	m_iResist = iNewValue;
}

void CvUnit::changeResist(int iChange)
{
	setResist(getResist() + iChange);
}

int CvUnit::getResistModify() const
{
	return m_iResistModify;
}

void CvUnit::setResistModify(int iNewValue)
{
	m_iResistModify = iNewValue;
}

void CvUnit::changeResistModify(int iChange)
{
	setResistModify(getResistModify() + iChange);
}

int CvUnit::getSpellCasterXP() const
{
/*************************************************************************************************/
/**	CasterXP (PromotionInfos)		05/25/08										Xienwolf	**/
/**																								**/
/**						Adds new Promotion Tag check to the old Unit Tag Check					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
    if (!m_pUnitInfo->isFreeXP())
								----  End Original Code  ----									**/
    if (!(m_pUnitInfo->isFreeXP() || isGetCasterXP()))
/*************************************************************************************************/
/**	CasterXP (PromotionInfos)					END												**/
/*************************************************************************************************/
    {
        return 0;
    }
	return m_iSpellCasterXP;
}

void CvUnit::changeSpellCasterXP(int iChange)
{
    if (iChange != 0)
    {
        m_iSpellCasterXP += iChange;
    }
}

int CvUnit::getSpellDamageModify() const
{
	return m_iSpellDamageModify;
}

void CvUnit::setSpellDamageModify(int iNewValue)
{
	m_iSpellDamageModify = iNewValue;
}

void CvUnit::changeSpellDamageModify(int iChange)
{
	setSpellDamageModify(getSpellDamageModify() + iChange);
}

bool CvUnit::isResisted(CvUnit* pCaster, int iSpell)
{
    if (GC.getGameINLINE().getSorenRandNum(100, "is Resisted") <= getResistChance(pCaster, iSpell))
    {
        gDLL->getInterfaceIFace()->addMessage(getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_RESISTED"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, "art/interface/buttons/promotions/magicresistance.dds", (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
        gDLL->getInterfaceIFace()->addMessage(pCaster->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), gDLL->getText("TXT_KEY_MESSAGE_SPELL_RESISTED"), "AS2D_DISCOVERBONUS", MESSAGE_TYPE_MAJOR_EVENT, "art/interface/buttons/promotions/magicresistance.dds", (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
        return true;
    }
    return false;
}

int CvUnit::getResistChance(CvUnit* pCaster, int iSpell)
{
    if (isImmuneToSpell(pCaster, iSpell))
    {
        return 100;
    }
    int iResist = GC.getDefineINT("SPELL_RESIST_CHANCE_BASE");
	iResist += getLevel() * 5;
    iResist += getResist();
    iResist += pCaster->getResistModify();
    iResist += GC.getSpellInfo((SpellTypes)iSpell).getResistModify();
    if (plot()->isCity())
    {
        iResist += plot()->getPlotCity()->getResistMagic();
    }
	if (iResist >= GC.getDefineINT("SPELL_RESIST_CHANCE_MAX"))
	{
		iResist = GC.getDefineINT("SPELL_RESIST_CHANCE_MAX");
	}
	if (iResist <= GC.getDefineINT("SPELL_RESIST_CHANCE_MIN"))
	{
		iResist = GC.getDefineINT("SPELL_RESIST_CHANCE_MIN");
	}
	return iResist;
}

void CvUnit::changeBaseCombatStr(int iChange)
{
	setBaseCombatStr(m_iBaseCombat + iChange);
}

void CvUnit::changeBaseCombatStrDefense(int iChange)
{
	setBaseCombatStrDefense(m_iBaseCombatDefense + iChange);
}

int CvUnit::getUnitArtStyleType() const
{
	return m_iUnitArtStyleType;
}

void CvUnit::setUnitArtStyleType(int iNewValue)
{
	m_iUnitArtStyleType = iNewValue;
}

int CvUnit::chooseSpell()
{
    int iBestSpell = -1;
    int iRange;
    int iTempValue;
    int iValue;
    int iBestSpellValue = 0;
    CvPlot* pLoopPlot;
    CvUnit* pLoopUnit;
    CLLNode<IDInfo>* pUnitNode;

    for (int iSpell = 0; iSpell < GC.getNumSpellInfos(); iSpell++)
    {
        iValue = 0;
        if (canCast(iSpell, false))
        {
            iRange = GC.getSpellInfo((SpellTypes)iSpell).getRange();
            if (GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType() != NO_UNIT)
            {
                int iMoveRange = GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getMoves() + getExtraSpellMove();
                bool bEnemy = false;
                for (int i = -iMoveRange; i <= iMoveRange; ++i)
                {
                    for (int j = -iMoveRange; j <= iMoveRange; ++j)
                    {
                        pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
                        if (NULL != pLoopPlot)
                        {
                            if (pLoopPlot->isVisibleEnemyUnit(this))
                            {
                                bEnemy = true;
                            }
                        }
                    }
                }
                if (bEnemy)
                {
                    iTempValue = GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getCombat();
                    for (int iI = 0; iI < GC.getNumDamageTypeInfos(); iI++)
                    {
                        iTempValue += GC.getUnitInfo((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitType()).getDamageTypeCombat(iI);
                    }
                    iTempValue *= 100;
                    iTempValue *= GC.getSpellInfo((SpellTypes)iSpell).getCreateUnitNum();
                    iValue += iTempValue;
                }
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getDamage() != 0)
            {
                int iDmg = GC.getSpellInfo((SpellTypes)iSpell).getDamage();
                int iDmgLimit = GC.getSpellInfo((SpellTypes)iSpell).getDamageLimit();
                for (int i = -iRange; i <= iRange; ++i)
                {
                    for (int j = -iRange; j <= iRange; ++j)
                    {
                        pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
                        if (NULL != pLoopPlot)
                        {
                            if (pLoopPlot->getX() != plot()->getX() || pLoopPlot->getY() != plot()->getY())
                            {
                                pUnitNode = pLoopPlot->headUnitNode();
                                while (pUnitNode != NULL)
                                {
                                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                                    if (!pLoopUnit->isImmuneToSpell(this, iSpell))
                                    {
                                        if (pLoopUnit->isEnemy(getTeam()))
                                        {
                                            if (pLoopUnit->getDamage() < iDmgLimit)
                                            {
                                                iValue += iDmg * 10;
                                            }
                                        }
                                        if (pLoopUnit->getTeam() == getTeam())
                                        {
                                            iValue -= iDmg * 20;
                                        }
                                        if (pLoopUnit->getTeam() != getTeam() && pLoopUnit->isEnemy(getTeam()) == false)
                                        {
                                            iValue -= 1000;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1() != NO_PROMOTION)
            {
                iValue += AI_promotionValue((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType1());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2() != NO_PROMOTION)
            {
                iValue += AI_promotionValue((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType2());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3() != NO_PROMOTION)
            {
                iValue += AI_promotionValue((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getAddPromotionType3());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getRemovePromotionType1() != NO_PROMOTION)
            {
                iValue -= AI_promotionValue((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getRemovePromotionType1());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getRemovePromotionType2() != NO_PROMOTION)
            {
                iValue -= AI_promotionValue((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getRemovePromotionType2());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getRemovePromotionType3() != NO_PROMOTION)
            {
                iValue -= AI_promotionValue((PromotionTypes)GC.getSpellInfo((SpellTypes)iSpell).getRemovePromotionType3());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getConvertUnitType() != NO_UNIT)
            {
                iValue += GET_PLAYER(getOwnerINLINE()).AI_unitValue((UnitTypes)GC.getSpellInfo((SpellTypes)iSpell).getConvertUnitType(), UNITAI_ATTACK, area());
                iValue -= GET_PLAYER(getOwnerINLINE()).AI_unitValue((UnitTypes)getUnitType(), UNITAI_ATTACK, area());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getCreateBuildingType() != NO_BUILDING)
            {
                iValue += plot()->getPlotCity()->AI_buildingValue((BuildingTypes)GC.getSpellInfo((SpellTypes)iSpell).getCreateBuildingType());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getCreateFeatureType() != NO_FEATURE)
            {
                iValue += 10;
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getCreateImprovementType() != NO_IMPROVEMENT)
            {
                iValue += 10;
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).isDispel())
            {
                iValue += 25 * (iRange + 1) * (iRange + 1);
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).isPush())
            {
                iValue += 20 * (iRange + 1) * (iRange + 1);
                if (plot()->isCity())
                {
                    iValue *= 3;
                }
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getChangePopulation() != 0)
            {
                iValue += 50 * GC.getSpellInfo((SpellTypes)iSpell).getChangePopulation();
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getCost() != 0)
            {
                iValue -= 4 * GC.getSpellInfo((SpellTypes)iSpell).getCost();
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).getImmobileTurns() != 0)
            {
                iValue += 20 * GC.getSpellInfo((SpellTypes)iSpell).getImmobileTurns() * (iRange + 1) * (iRange + 1);
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).isSacrificeCaster())
            {
                iValue -= getLevel() * GET_PLAYER(getOwnerINLINE()).AI_unitValue((UnitTypes)getUnitType(), UNITAI_ATTACK, area());
            }
            if (GC.getSpellInfo((SpellTypes)iSpell).isResistable())
            {
                iValue /= 2;
            }
            iValue += GC.getSpellInfo((SpellTypes)iSpell).getAIWeight();
            if (iValue > iBestSpellValue)
            {
                iBestSpellValue = iValue;
                iBestSpell = iSpell;
            }
        }
    }
    return iBestSpell;
}

int CvUnit::getExtraSpellMove()
{
    int iCount = 0;
	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
	    if (isHasPromotion((PromotionTypes)iI))
	    {
	        if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk() != NO_PROMOTION)
	        {
	            iCount += GC.getPromotionInfo((PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionSummonPerk()).getMovesChange();
	        }
	    }
	}
	return iCount;
}

void CvUnit::doDamage(int iDmg, int iDmgLimit, CvUnit* pAttacker, int iDmgType, bool bStartWar)
{
    CvWString szMessage;
    int iResist;

    iResist = baseCombatStr() *2;
    iResist += getLevel() * 2;
    if (iDmgType != -1)
    {
        iResist += getDamageTypeResist((DamageTypes)iDmgType);
    }
    if (pAttacker != NULL)
    {
        iDmg += pAttacker->getSpellDamageModify();
    }
    if (iResist < 100)
    {
        iDmg = GC.getGameINLINE().getSorenRandNum(iDmg, "Damage") + GC.getGameINLINE().getSorenRandNum(iDmg, "Damage");
		iDmg = iDmg * (100 - iResist) / 100;

        if (iDmg + getDamage() > iDmgLimit)
        {
            iDmg = iDmgLimit - getDamage();
        }
        if (iDmg > 0)
        {
            if (iDmg + getDamage() >= GC.getMAX_HIT_POINTS())
            {
                szMessage = gDLL->getText("TXT_KEY_MESSAGE_KILLED_BY", m_pUnitInfo->getDescription(), GC.getDamageTypeInfo((DamageTypes)iDmgType).getDescription());
            }
            else
            {
                szMessage = gDLL->getText("TXT_KEY_MESSAGE_DAMAGED_BY", m_pUnitInfo->getDescription(), iDmg, GC.getDamageTypeInfo((DamageTypes)iDmgType).getDescription());
            }
            gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)getOwner()), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szMessage, "", MESSAGE_TYPE_MAJOR_EVENT, GC.getDamageTypeInfo((DamageTypes)iDmgType).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
            if (pAttacker != NULL)
            {
                gDLL->getInterfaceIFace()->addMessage(((PlayerTypes)pAttacker->getOwner()), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szMessage, "", MESSAGE_TYPE_MAJOR_EVENT, GC.getDamageTypeInfo((DamageTypes)iDmgType).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                changeDamage(iDmg, pAttacker->getOwner());
                if (getDamage() >= GC.getMAX_HIT_POINTS())
                {
                    kill(true,pAttacker->getOwner());
                }
                if (bStartWar)
                {
                    if (!(pAttacker->isHiddenNationality()) && !(isHiddenNationality()))
                    {
                        if (getTeam() != pAttacker->getTeam())
                        {
                            GET_TEAM(pAttacker->getTeam()).declareWar(getTeam(), false, NO_WARPLAN);
                        }
                    }
                }
            }
            else
            {
                changeDamage(iDmg, NO_PLAYER);
                if (getDamage() >= GC.getMAX_HIT_POINTS())
                {
                    if (isImmortal())
                    {
                        doImmortalRebirth();
                    }
                    else
                    {
                        kill(true,NO_PLAYER);
                    }
                }
            }
        }
    }
}

void CvUnit::doEscape()
{
    if (GET_PLAYER(getOwnerINLINE()).getCapitalCity() != NULL)
    {
        setXY(GET_PLAYER(getOwnerINLINE()).getCapitalCity()->getX(), GET_PLAYER(getOwnerINLINE()).getCapitalCity()->getY(), false, true, true);
    }
}

void CvUnit::doImmortalRebirth()
{
    setDamage(75, NO_PLAYER);
   	for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
	{
        if (isHasPromotion((PromotionTypes)iI))
        {
            if (GC.getPromotionInfo((PromotionTypes)iI).isImmortal())
            {
                setHasPromotion(((PromotionTypes)iI), false);
                break;
            }
		}
	}
    setImmortal(false);
    doEscape();
}

void CvUnit::combatWon(CvUnit* pLoser, bool bAttacking)
{
    PromotionTypes ePromotion;
    bool bConvert = false;
    int iUnit = NO_UNIT;
/*************************************************************************************************/
/**	Xienwolf Tweak								TWEAK											**/
/**																								**/
/**							Display information for Unit Capture/Conversion						**/
/*************************************************************************************************/
    int iNew = NO_UNIT;
/*************************************************************************************************/
/**	Xienwolf Tweak  							END												**/
/*************************************************************************************************/
    CLLNode<IDInfo>* pUnitNode;
    CvUnit* pLoopUnit;
    CvPlot* pPlot;
    CvUnit* pUnit;

    for (int iI = 0; iI < GC.getNumPromotionInfos(); iI++)
    {
        if (isHasPromotion((PromotionTypes)iI))
        {
            if (GC.getPromotionInfo((PromotionTypes)iI).getFreeXPFromCombat() != 0)
            {
                changeExperience(GC.getPromotionInfo((PromotionTypes)iI).getFreeXPFromCombat(), -1, false, false, false);
            }
            if (GC.getPromotionInfo((PromotionTypes)iI).isRemovedByCombat())
            {
                setHasPromotion(((PromotionTypes)iI), false);
		    }
            if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionCombatApply() != NO_PROMOTION)
            {
                ePromotion = (PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionCombatApply();
                pPlot = pLoser->plot();
                pUnitNode = pPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pPlot->nextUnitNode(pUnitNode);
                    if (pLoopUnit->isHasPromotion(ePromotion) == false)
                    {
                        if (pLoopUnit->isAlive() || !GC.getPromotionInfo(ePromotion).isPrereqAlive())
                        {
                            if (isEnemy(pLoopUnit->getTeam()))
                            {
                                if (pLoopUnit->canAcquirePromotion(ePromotion))
                                {
                                    if (GC.getGameINLINE().getSorenRandNum(100, "Combat Apply") <= GC.getDefineINT("COMBAT_APPLY_CHANCE"))
                                    {
                                        pLoopUnit->setHasPromotion(ePromotion, true);
                                        gDLL->getInterfaceIFace()->addMessage((PlayerTypes)pLoopUnit->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), GC.getPromotionInfo(ePromotion).getDescription(), "", MESSAGE_TYPE_INFO, GC.getPromotionInfo(ePromotion).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                                        gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), true, GC.getEVENT_MESSAGE_TIME(), GC.getPromotionInfo(ePromotion).getDescription(), "", MESSAGE_TYPE_INFO, GC.getPromotionInfo(ePromotion).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (GC.getPromotionInfo((PromotionTypes)iI).getCombatCapturePercent() != 0)
            {
                if (iUnit == NO_UNIT && pLoser->isAlive())
                {
                    if (GC.getGameINLINE().getSorenRandNum(100, "Combat Capture") <= GC.getPromotionInfo((PromotionTypes)iI).getCombatCapturePercent())
                    {
                        iUnit = pLoser->getUnitType();
                        bConvert = true;
                    }
                }
            }
            if (GC.getPromotionInfo((PromotionTypes)iI).getCaptureUnitCombat() != NO_UNITCOMBAT)
            {
                if (iUnit == NO_UNIT && pLoser->getUnitCombatType() == GC.getPromotionInfo((PromotionTypes)iI).getCaptureUnitCombat())
                {
                    iUnit = pLoser->getUnitType();
                    bConvert = true;
                }
            }
		}
        if (pLoser->isHasPromotion((PromotionTypes)iI))
        {
            if (GC.getPromotionInfo((PromotionTypes)iI).getPromotionCombatApply() != NO_PROMOTION)
            {
                ePromotion = (PromotionTypes)GC.getPromotionInfo((PromotionTypes)iI).getPromotionCombatApply();
                if (isHasPromotion(ePromotion) == false)
                {
                    if (isAlive() || !GC.getPromotionInfo(ePromotion).isPrereqAlive())
                    {
                        if (pLoser->isEnemy(getTeam()))
                        {
                            if (GC.getGameINLINE().getSorenRandNum(100, "Combat Apply") <= GC.getDefineINT("COMBAT_APPLY_CHANCE"))
                            {
                                setHasPromotion(ePromotion, true);
                                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)getOwner(), true, GC.getEVENT_MESSAGE_TIME(), GC.getPromotionInfo(ePromotion).getDescription(), "", MESSAGE_TYPE_INFO, GC.getPromotionInfo(ePromotion).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), getX_INLINE(), getY_INLINE(), true, true);
                                gDLL->getInterfaceIFace()->addMessage((PlayerTypes)pLoser->getOwner(), true, GC.getEVENT_MESSAGE_TIME(), GC.getPromotionInfo(ePromotion).getDescription(), "", MESSAGE_TYPE_INFO, GC.getPromotionInfo(ePromotion).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true);
                            }
                        }
                    }
                }
		    }
        }
	}
    if (GET_PLAYER(getOwnerINLINE()).getFreeXPFromCombat() != 0)
    {
        changeExperience(GET_PLAYER(getOwnerINLINE()).getFreeXPFromCombat(), -1, false, false, false);
    }
    if (getCombatHealPercent() != 0)
    {
        int i = getCombatHealPercent();
        if (i > getDamage())
        {
            i = getDamage();
        }
        if (i != 0)
        {
            changeDamage(-1 * i, NO_PLAYER);
        }
    }
    if (m_pUnitInfo->isExplodeInCombat() && m_pUnitInfo->isSuicide())
    {
        if (bAttacking)
        {
            pPlot = pLoser->plot();
        }
        else
        {
            pPlot = plot();
        }
        if (plot()->isVisibleToWatchingHuman())
        {
            gDLL->getEngineIFace()->TriggerEffect((EffectTypes)GC.getInfoTypeForString("EFFECT_ARTILLERY_SHELL_EXPLODE"), pPlot->getPoint(), (float)(GC.getASyncRand().get(360)));
            gDLL->getInterfaceIFace()->playGeneralSound("AS3D_UN_GRENADE_EXPLODE", pPlot->getPoint());
        }
    }
    if (GC.getUnitInfo(pLoser->getUnitType()).isExplodeInCombat())
    {
//WH:Modify Ploeperpengel Magic Missle Effects based on damagetype
        int iFireDamage = GC.getInfoTypeForString("DAMAGE_FIRE");
		int iDarkDamage = GC.getInfoTypeForString("DAMAGE_UNHOLY");
		int iHighDamage = GC.getInfoTypeForString("DAMAGE_HOLY");
		if (plot()->isVisibleToWatchingHuman() && (GC.getUnitInfo(pLoser->getUnitType()).getDamageTypeCombat(iFireDamage) > 0 )) 
		{
			gDLL->getEngineIFace()->TriggerEffect((EffectTypes)GC.getInfoTypeForString("EFFECT_ARTILLERY_SHELL_EXPLODE"), plot()->getPoint(), (float)(GC.getASyncRand().get(360)));
			gDLL->getInterfaceIFace()->playGeneralSound("AS3D_UN_GRENADE_EXPLODE", plot()->getPoint());
		}
		if (plot()->isVisibleToWatchingHuman() && (GC.getUnitInfo(pLoser->getUnitType()).getDamageTypeCombat(iDarkDamage) > 0 )) 
		{
			gDLL->getEngineIFace()->TriggerEffect((EffectTypes)GC.getInfoTypeForString("EFFECT_DARKMAGIC_EXPLODE"), plot()->getPoint(), (float)(GC.getASyncRand().get(360)));
			gDLL->getInterfaceIFace()->playGeneralSound("AS3D_SPELL_CONTAGION", plot()->getPoint());
		}
		if (plot()->isVisibleToWatchingHuman() && (GC.getUnitInfo(pLoser->getUnitType()).getDamageTypeCombat(iHighDamage) > 0 )) 
		{
			gDLL->getEngineIFace()->TriggerEffect((EffectTypes)GC.getInfoTypeForString("EFFECT_HIGHMAGIC_EXPLODE"), plot()->getPoint(), (float)(GC.getASyncRand().get(360)));
			gDLL->getInterfaceIFace()->playGeneralSound("AS3D_SPELL_BANISH", plot()->getPoint());
		}
		else if (plot()->isVisibleToWatchingHuman())
        {
            gDLL->getEngineIFace()->TriggerEffect((EffectTypes)GC.getInfoTypeForString("EFFECT_ARTILLERY_SHELL_EXPLODE"), pPlot->getPoint(), (float)(GC.getASyncRand().get(360)));
            gDLL->getInterfaceIFace()->playGeneralSound("AS3D_UN_GRENADE_EXPLODE", pPlot->getPoint());
        }
//WH: End Modify
	}
/*************************************************************************************************/
/**	Slavers							05/19/08										Xienwolf	**/
/**																								**/
/**					Adds Promotion Field to other Chances for Slave Generation					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
    if ((m_pUnitInfo->getEnslavementChance() + GET_PLAYER(getOwnerINLINE()).getEnslavementChance()) > 0)
								----  End Original Code  ----									**/
    if ((getSlaveGenerationChance() + m_pUnitInfo->getEnslavementChance() + GET_PLAYER(getOwnerINLINE()).getEnslavementChance()) > 0)
    {
        if (getDuration() == 0 && pLoser->isAlive() && !pLoser->isAnimal() && iUnit == NO_UNIT)
        {
/**								---- Start Original Code ----
            if (GC.getGameINLINE().getSorenRandNum(100, "Enslavement") <= (m_pUnitInfo->getEnslavementChance() + GET_PLAYER(getOwnerINLINE()).getEnslavementChance()))
								----  End Original Code  ----									**/
            if (GC.getGameINLINE().getSorenRandNum(100, "Enslavement") <= (getSlaveGenerationChance() + m_pUnitInfo->getEnslavementChance() + GET_PLAYER(getOwnerINLINE()).getEnslavementChance()))
/*************************************************************************************************/
/**	Slavers										END												**/
/*************************************************************************************************/
            {
                iUnit = GC.getCivilizationInfo(pLoser->getCivilizationType()).getCivilizationUnits((UnitClassTypes)GC.getDefineINT("SLAVE_UNITCLASS"));
            }
        }
    }
    if (m_pUnitInfo->getPromotionFromCombat() != NO_PROMOTION)
    {
        if (pLoser->isAlive())
        {
            setHasPromotion((PromotionTypes)m_pUnitInfo->getPromotionFromCombat(), true);
        }
    }
    if (m_pUnitInfo->getGoldFromCombat() != 0)
    {
        GET_PLAYER(getOwnerINLINE()).changeGold(m_pUnitInfo->getGoldFromCombat());
    }
    if (getDuration() > 0)
    {
/*************************************************************************************************/
/**	StayingPower					05/19/08										Xienwolf	**/
/**																								**/
/**							Adds Promotion Field to Duration change								**/
/*************************************************************************************************/
/**								---- Start Original Code ----
        changeDuration(m_pUnitInfo->getDurationFromCombat());
								----  End Original Code  ----									**/
        changeDuration(m_pUnitInfo->getDurationFromCombat() + getCombatExtraDuration());

        if (getDuration() <= 0)
        {
            setDuration(0);
        }
/*************************************************************************************************/
/**	StayingPower								END												**/
/*************************************************************************************************/
    }
    if (pLoser->getDamageTypeCombat(DAMAGE_POISON) > 0 && GC.getDefineINT("POISONED_PROMOTION") != -1)
    {
        if (isAlive() && getDamage() > 0)
        {
            if (GC.getGameINLINE().getSorenRandNum(100, "Poisoned") >= pLoser->getDamageTypeResist(DAMAGE_POISON))
            {
                setHasPromotion((PromotionTypes)GC.getDefineINT("POISONED_PROMOTION"), true);
            }
        }
    }
    if (m_pUnitInfo->getUnitCreateFromCombat() != NO_UNIT)
    {
        if (!pLoser->isImmuneToCapture() && pLoser->isAlive() && GC.getUnitInfo((UnitTypes)pLoser->getUnitType()).getEquipmentPromotion() == NO_PROMOTION)
        {
            if (GC.getGameINLINE().getSorenRandNum(100, "Create Unit from Combat") <= m_pUnitInfo->getUnitCreateFromCombatChance())
            {
/*************************************************************************************************/
/**	Xienwolf Tweak								TWEAK											**/
/**																								**/
/**							Display information for Unit Capture/Conversion						**/
/*************************************************************************************************/
                iNew = m_pUnitInfo->getUnitCreateFromCombat();
/*************************************************************************************************/
/**	Xienwolf Tweak  							END												**/
/*************************************************************************************************/
                pUnit = GET_PLAYER(getOwnerINLINE()).initUnit((UnitTypes)m_pUnitInfo->getUnitCreateFromCombat(), plot()->getX_INLINE(), plot()->getY_INLINE());
                if (isHiddenNationality())
                {
                    pUnit->setHasPromotion((PromotionTypes)GC.getDefineINT("HIDDEN_NATIONALITY_PROMOTION"), true);
                }
                iUnit = NO_UNIT;
            }
        }
    }
    if (iUnit != NO_UNIT)
    {
        if ((!pLoser->isImmuneToCapture() && !isNoCapture()) || GC.getUnitInfo((UnitTypes)pLoser->getUnitType()).getEquipmentPromotion() != NO_PROMOTION)
        {
/*************************************************************************************************/
/**	Xienwolf Tweak								TWEAK											**/
/**																								**/
/**							Display information for Unit Capture/Conversion						**/
/*************************************************************************************************/
            iNew = iUnit;
/*************************************************************************************************/
/**	Xienwolf Tweak  							END												**/
/*************************************************************************************************/
            pUnit = GET_PLAYER(getOwnerINLINE()).initUnit((UnitTypes)iUnit, plot()->getX_INLINE(), plot()->getY_INLINE());

/*************************************************************************************************/
/**	Xienwolf Tweak								TWEAK											**/
/**																								**/
/**						Doesn't make much sense for Duration to be passed on					**/
/*************************************************************************************************/
/**								---- Start Original Code ----
            if (getDuration() != 0)
            {
                pUnit->setDuration(getDuration());
            }
								----  End Original Code  ----									**/
/*************************************************************************************************/
/**	Xienwolf Tweak  							END												**/
/*************************************************************************************************/

            if (bConvert)
            {
                pLoser->setDamage(75, NO_PLAYER, false);
                pUnit->convert(pLoser);
            }
        }
    }
/*************************************************************************************************/
/**	Xienwolf Tweak								TWEAK											**/
/**																								**/
/**							Display information for Unit Capture/Conversion						**/
/*************************************************************************************************/
    if (iNew != NO_UNIT)
    {
        iUnit = iNew;
        CvWString szBuffer;

        szBuffer = gDLL->getText("TXT_KEY_SLAVE_CAPTURED", GC.getUnitInfo((UnitTypes)iUnit).getTextKeyWide(), GET_PLAYER(pLoser->getOwnerINLINE()).getCivilizationAdjectiveKey(), pLoser->getNameKey(), GET_PLAYER(pLoser->getOwnerINLINE()).getNameKey());
        gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_YELLOW"), getX_INLINE(), getY_INLINE());
    }
/*************************************************************************************************/
/**	Xienwolf Tweak  							END												**/
/*************************************************************************************************/
    if (!isEmpty(GC.getUnitInfo(getUnitType()).getPyPostCombatWon()))
    {
        CyUnit* pyCaster = new CyUnit(this);
        CyUnit* pyOpponent = new CyUnit(pLoser);
        CyArgsList argsList;
        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyCaster));	// pass in unit class
        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyOpponent));	// pass in unit class
        gDLL->getPythonIFace()->callFunction(PYSpellModule, "postCombatWon", argsList.makeFunctionArgs()); //, &lResult
        delete pyCaster; // python fxn must not hold on to this pointer
        delete pyOpponent; // python fxn must not hold on to this pointer
    }
    if (!isEmpty(GC.getUnitInfo(pLoser->getUnitType()).getPyPostCombatLost()))
    {
        CyUnit* pyCaster = new CyUnit(pLoser);
        CyUnit* pyOpponent = new CyUnit(this);
        CyArgsList argsList;
        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyCaster));	// pass in unit class
        argsList.add(gDLL->getPythonIFace()->makePythonObject(pyOpponent));	// pass in unit class
        gDLL->getPythonIFace()->callFunction(PYSpellModule, "postCombatLost", argsList.makeFunctionArgs()); //, &lResult
        delete pyCaster; // python fxn must not hold on to this pointer
        delete pyOpponent; // python fxn must not hold on to this pointer
    }
    if (m_pUnitInfo->getUnitConvertFromCombat() != NO_UNIT)
    {
        if (GC.getGameINLINE().getSorenRandNum(100, "Convert Unit from Combat") <= m_pUnitInfo->getUnitConvertFromCombatChance())
        {
            pUnit = GET_PLAYER(getOwnerINLINE()).initUnit((UnitTypes)m_pUnitInfo->getUnitConvertFromCombat(), getX_INLINE(), getY_INLINE(), AI_getUnitAIType());
            pUnit->convert(this);
        }
    }
}

void CvUnit::setWeapons()
{
	CvPlot* pPlot;
	CvCity* pCity;
    if (GC.getDefineINT("WEAPON_PROMOTION_TIER1") == -1)
    {
        return;
    }
	pPlot = plot();
    if (pPlot->isCity())
    {
        pCity = pPlot->getPlotCity();
        if (pCity->getOwner() == getOwner())
        {
            PromotionTypes ePromT1 = (PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER1");
            PromotionTypes ePromT2 = (PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER2");
            PromotionTypes ePromT3 = (PromotionTypes)GC.getDefineINT("WEAPON_PROMOTION_TIER3");
            if (isHasPromotion(ePromT3) == false)
            {
                if (pCity->hasBonus((BonusTypes)GC.getDefineINT("WEAPON_REQ_BONUS_TIER3")) &&
                  m_pUnitInfo->getWeaponTier() >= 3)
                {
                    setHasPromotion(ePromT3, true);
                    gDLL->getInterfaceIFace()->addMessage(getOwner(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), gDLL->getText("TXT_KEY_MESSAGE_WEAPONS_MITHRIL"), "AS2D_REPAIR", MESSAGE_TYPE_MAJOR_EVENT, GC.getPromotionInfo(ePromT3).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX(), getY(), true, true);
                    setHasPromotion(ePromT2, false);
                    setHasPromotion(ePromT1, false);
                }
                else
                {
                    if (isHasPromotion(ePromT2) == false)
                    {
                        if (pCity->hasBonus((BonusTypes)GC.getDefineINT("WEAPON_REQ_BONUS_TIER2")) &&
                          m_pUnitInfo->getWeaponTier() >= 2)
                        {
                            setHasPromotion(ePromT2, true);
                            gDLL->getInterfaceIFace()->addMessage(getOwner(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), gDLL->getText("TXT_KEY_MESSAGE_WEAPONS_IRON"), "AS2D_REPAIR", MESSAGE_TYPE_MAJOR_EVENT, GC.getPromotionInfo(ePromT2).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX(), getY(), true, true);
                            setHasPromotion(ePromT1, false);
                        }
                        else
                        {
                            if (isHasPromotion(ePromT1) == false)
                            {
                                if (pCity->hasBonus((BonusTypes)GC.getDefineINT("WEAPON_REQ_BONUS_TIER1")) &&
                                  m_pUnitInfo->getWeaponTier() >= 1)
                                {
                                    gDLL->getInterfaceIFace()->addMessage(getOwner(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), gDLL->getText("TXT_KEY_MESSAGE_WEAPONS_BRONZE"), "AS2D_REPAIR", MESSAGE_TYPE_MAJOR_EVENT, GC.getPromotionInfo(ePromT1).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX(), getY(), true, true);
                                    setHasPromotion(ePromT1, true);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

void CvUnit::changeBonusAffinity(BonusTypes eIndex, int iChange)
{
    if (iChange != 0)
    {
        m_paiBonusAffinity[eIndex] += iChange;
    }
    updateBonusAffinity(eIndex);
}

int CvUnit::getBonusAffinity(BonusTypes eIndex) const
{
	return m_paiBonusAffinity[eIndex];
}

void CvUnit::updateBonusAffinity(BonusTypes eIndex)
{
    int iNew = GET_PLAYER(getOwnerINLINE()).getNumAvailableBonuses(eIndex) * getBonusAffinity(eIndex);
    int iOld = m_paiBonusAffinityAmount[eIndex];
    if (GC.getBonusInfo(eIndex).getDamageType() == NO_DAMAGE)
    {
        m_iBaseCombat += iNew - iOld;
        m_iBaseCombatDefense += iNew - iOld;
    }
    else
    {
        m_paiDamageTypeCombat[GC.getBonusInfo(eIndex).getDamageType()] += iNew - iOld;
        m_iTotalDamageTypeCombat += iNew - iOld;
    }
    m_paiBonusAffinityAmount[eIndex] = iNew;
}

void CvUnit::changeDamageTypeCombat(DamageTypes eIndex, int iChange)
{
    if (iChange != 0)
    {
        m_paiDamageTypeCombat[eIndex] = (m_paiDamageTypeCombat[eIndex] + iChange);
        m_iTotalDamageTypeCombat = (m_iTotalDamageTypeCombat + iChange);
    }
}

int CvUnit::getDamageTypeCombat(DamageTypes eIndex) const
{
	return m_paiDamageTypeCombat[eIndex];
}

int CvUnit::getTotalDamageTypeCombat() const
{
    return m_iTotalDamageTypeCombat;
}

int CvUnit::getDamageTypeResist(DamageTypes eIndex) const
{
    int i = m_paiDamageTypeResist[eIndex];
    if (i <= -100)
    {
        return -100;
    }
    if (i >= 100)
    {
        return 100;
    }
	return i;
}

void CvUnit::changeDamageTypeResist(DamageTypes eIndex, int iChange)
{
    if (iChange != 0)
    {
        m_paiDamageTypeResist[eIndex] = (m_paiDamageTypeResist[eIndex] + iChange);
    }
}

int CvUnit::countUnitsWithinRange(int iRange, bool bEnemy, bool bNeutral, bool bTeam)
{
    CLLNode<IDInfo>* pUnitNode;
    CvUnit* pLoopUnit;
    CvPlot* pLoopPlot;
    int iCount = 0;
    for (int i = -iRange; i <= iRange; ++i)
    {
        for (int j = -iRange; j <= iRange; ++j)
        {
            pLoopPlot = ::plotXY(plot()->getX_INLINE(), plot()->getY_INLINE(), i, j);
            if (NULL != pLoopPlot)
            {
                pUnitNode = pLoopPlot->headUnitNode();
                while (pUnitNode != NULL)
                {
                    pLoopUnit = ::getUnit(pUnitNode->m_data);
                    pUnitNode = pLoopPlot->nextUnitNode(pUnitNode);
                    if (bTeam && pLoopUnit->getTeam() == getTeam())
                    {
                        iCount += 1;
                    }
                    if (bEnemy && atWar(pLoopUnit->getTeam(), getTeam()))
                    {
                        iCount += 1;
                    }
                    if (bNeutral && pLoopUnit->getTeam() != getTeam() && !atWar(pLoopUnit->getTeam(), getTeam()))
                    {
                        iCount += 1;
                    }
                }
            }
        }
    }
    return iCount;
}

CvPlot* CvUnit::getOpenPlot()
{
	CvPlot* pLoopPlot;
	CvPlot* pBestPlot = NULL;
	int iValue;
	int iBestValue = MAX_INT;
	for (int iI = 0; iI < GC.getMapINLINE().numPlotsINLINE(); iI++)
	{
		pLoopPlot = GC.getMapINLINE().plotByIndexINLINE(iI);
		if (pLoopPlot->isValidDomainForLocation(*this))
		{
			if (canMoveInto(pLoopPlot))
			{
				if (pLoopPlot->getNumUnits() == 0)
				{
                    iValue = plotDistance(getX_INLINE(), getY_INLINE(), pLoopPlot->getX_INLINE(), pLoopPlot->getY_INLINE()) * 2;
                    if (pLoopPlot->area() != area())
                    {
                        iValue *= 3;
                    }
                    if (iValue < iBestValue)
                    {
                        iBestValue = iValue;
                        pBestPlot = pLoopPlot;
					}
				}
			}
		}
	}
	return pBestPlot;
}

void CvUnit::betray(PlayerTypes ePlayer)
{
   	if (getOwnerINLINE() == ePlayer)
	{
		return;
	}
    CvPlot* pNewPlot = getOpenPlot();
    if (pNewPlot != NULL)
    {
        CvUnit* pUnit = GET_PLAYER(ePlayer).initUnit((UnitTypes)getUnitType(), pNewPlot->getX(), pNewPlot->getY(), AI_getUnitAIType());
        pUnit->convert(this);
        if (pUnit->getDuration() > 0)
        {
            pUnit->setDuration(0);
        }
    }
}
//FfH: End Add

void CvUnit::read(FDataStreamBase* pStream)
{
	// Init data before load
	reset();

	uint uiFlag=0;
	pStream->Read(&uiFlag);	// flags for expansion

	pStream->Read(&m_iID);
	pStream->Read(&m_iGroupID);
	pStream->Read(&m_iHotKeyNumber);
	pStream->Read(&m_iX);
	pStream->Read(&m_iY);
	pStream->Read(&m_iLastMoveTurn);
	pStream->Read(&m_iReconX);
	pStream->Read(&m_iReconY);
	pStream->Read(&m_iGameTurnCreated);
	pStream->Read(&m_iDamage);
	pStream->Read(&m_iMoves);
	pStream->Read(&m_iExperience);
	pStream->Read(&m_iLevel);
	pStream->Read(&m_iCargo);
	pStream->Read(&m_iCargoCapacity);
	pStream->Read(&m_iAttackPlotX);
	pStream->Read(&m_iAttackPlotY);
	pStream->Read(&m_iCombatTimer);
	pStream->Read(&m_iCombatFirstStrikes);
	pStream->Read(&m_iCombatDamage);
	pStream->Read(&m_iFortifyTurns);
	pStream->Read(&m_iBlitzCount);
	pStream->Read(&m_iAmphibCount);
	pStream->Read(&m_iRiverCount);
/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**										Read Data from Save File								**/
/*************************************************************************************************/
	pStream->Read(&m_iTerritorialCount);
	pStream->Read(&m_iRivalTerritoryExploreCount);
	pStream->Read(&m_iRivalTerritoryBlockCount);
	pStream->Read(&m_iPillageOnMoveCount);
	pStream->Read(&m_iSelfPillageCount);
	pStream->Read(&m_iGetCasterXPCount);
	pStream->Read(&m_iNonWarWearinessCount);
	pStream->Read(&m_iNoMapRevealCount);
	pStream->Read(&m_iCannotCaptureCount);
	pStream->Read(&m_iCityHappyCount);
	pStream->Read(&m_iCityNoHappyCount);
	pStream->Read(&m_iNoSupportCount);
	pStream->Read(&m_iCanPillageCount);
	pStream->Read(&m_iCannotPillageCount);
	pStream->Read(&m_iCitySpyCount);
	pStream->Read(&m_iStartGoldenAgeCount);
	pStream->Read(&m_iNoDefenseBonusCount);
	pStream->Read(&m_iMoveImpassableCount);
	pStream->Read(&m_iFlatMoveCostCount);
	pStream->Read(&m_iIgnoreTerrainCostsCount);
	pStream->Read(&m_iAttackNoWarCount);
	pStream->Read(&m_iAllowAttacksCount);
	pStream->Read(&m_iFirstStrikeVulnerableCount);
	pStream->Read(&m_iAllowDefenseBonusesCount);
	pStream->Read(&m_iNonAbandonCount);
	pStream->Read(&m_iIndependantCount);

	pStream->Read(&m_iWorkRateChange);
	pStream->Read(&m_iCombatConversionChance);
	pStream->Read(&m_iCombatUnitGenerationChance);
	pStream->Read(&m_iSlaveGenerationChance);
	pStream->Read(&m_iGiftableXP);
	pStream->Read(&m_iCombatExtraDuration);
	pStream->Read(&m_iDurationPerTurn);
	pStream->Read(&m_iChangeDuration);
	pStream->Read(&m_bNonTemporary);
	pStream->Read(&m_iExtraSupport);
	pStream->Read(&m_iChanceMiscast);
	pStream->Read(&m_iCombatDmgCap);
	pStream->Read(&m_iCombatDmgCapBoost);
	pStream->Read(&m_iCollateralLimitCap);
	pStream->Read(&m_iCollateralLimitBoost);
	pStream->Read(&m_iCollateralTargetsLimit);
	pStream->Read(&m_iCollateralExtraTargets);
	pStream->Read(&m_iHammerSacrifice);
	pStream->Read(&m_iExtraHammerPerPop);
	pStream->Read(&m_iFoodSacrifice);
	pStream->Read(&m_iPopulationAdd);
	pStream->Read(&m_iBeakerSacrifice);
	pStream->Read(&m_iExtraBeakerPerPop);
	pStream->Read(&m_iGoldSacrifice);
	pStream->Read(&m_iExtraGoldPerPop);
	pStream->Read(&m_iCultureSacrifice);
	pStream->Read(&m_iExtraCulturePerPop);

	pStream->Read(NUM_YIELD_TYPES, m_piYieldFromWin);
	pStream->Read(NUM_YIELD_TYPES, m_piYieldForLoss);
	pStream->Read(NUM_COMMERCE_TYPES, m_piCommerceFromWin);
	pStream->Read(NUM_COMMERCE_TYPES, m_piCommerceForLoss);
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
	pStream->Read(&m_iEnemyRouteCount);
	pStream->Read(&m_iAlwaysHealCount);
	pStream->Read(&m_iHillsDoubleMoveCount);
	pStream->Read(&m_iImmuneToFirstStrikesCount);
	pStream->Read(&m_iExtraVisibilityRange);
	pStream->Read(&m_iExtraMoves);
	pStream->Read(&m_iExtraMoveDiscount);
	pStream->Read(&m_iExtraAirRange);
	pStream->Read(&m_iExtraIntercept);
	pStream->Read(&m_iExtraEvasion);
	pStream->Read(&m_iExtraFirstStrikes);
	pStream->Read(&m_iExtraChanceFirstStrikes);
	pStream->Read(&m_iExtraWithdrawal);
	pStream->Read(&m_iExtraCollateralDamage);
	pStream->Read(&m_iExtraBombardRate);
	pStream->Read(&m_iExtraEnemyHeal);
	pStream->Read(&m_iExtraNeutralHeal);
	pStream->Read(&m_iExtraFriendlyHeal);
	pStream->Read(&m_iSameTileHeal);
	pStream->Read(&m_iAdjacentTileHeal);
	pStream->Read(&m_iExtraCombatPercent);
	pStream->Read(&m_iExtraCityAttackPercent);
	pStream->Read(&m_iExtraCityDefensePercent);
	pStream->Read(&m_iExtraHillsAttackPercent);
	pStream->Read(&m_iExtraHillsDefensePercent);
	pStream->Read(&m_iRevoltProtection);
	pStream->Read(&m_iCollateralDamageProtection);
	pStream->Read(&m_iPillageChange);
	pStream->Read(&m_iUpgradeDiscount);
	pStream->Read(&m_iExperiencePercent);
	pStream->Read(&m_iKamikazePercent);
	pStream->Read(&m_iBaseCombat);
	pStream->Read((int*)&m_eFacingDirection);
	pStream->Read(&m_iImmobileTimer);

	pStream->Read(&m_bMadeAttack);
	pStream->Read(&m_bMadeInterception);
	pStream->Read(&m_bPromotionReady);
	pStream->Read(&m_bDeathDelay);
	pStream->Read(&m_bCombatFocus);
	// m_bInfoBarDirty not saved...
	pStream->Read(&m_bBlockading);
	if (uiFlag > 0)
	{
		pStream->Read(&m_bAirCombat);
	}

//FfH Spell System: Added by Kael 07/23/2007
	pStream->Read(&m_bAlive);
	pStream->Read(&m_bBoarding);
	pStream->Read(&m_bDoubleFortifyBonus);
	pStream->Read(&m_bFear);
	pStream->Read(&m_bFleeImmortal);
	pStream->Read(&m_bFleeWithdrawl);
	pStream->Read(&m_bFlying);
	pStream->Read(&m_bHasCasted);
	pStream->Read(&m_bHiddenNationality);
	pStream->Read(&m_bIgnoreBuildingDefense);
	pStream->Read(&m_bImmortal);
	pStream->Read(&m_bImmuneToCapture);
	pStream->Read(&m_bImmuneToFear);
	pStream->Read(&m_bImmuneToMagic);
	pStream->Read(&m_bOnlyDefensive);
	pStream->Read(&m_bTargetWeakestUnit);
	pStream->Read(&m_bTargetWeakestUnitCounter);
	pStream->Read(&m_bTwincast);
	pStream->Read(&m_bWaterWalking);
	pStream->Read(&m_iBaseCombatDefense);
	pStream->Read(&m_iBetterDefenderThanPercent);
	pStream->Read(&m_iCombatHealPercent);
	pStream->Read(&m_iCombatLimit);
	pStream->Read(&m_iCombatPercentInBorders);
	pStream->Read(&m_iCombatPercentGlobalCounter);
	pStream->Read(&m_iDelayedSpell);
	pStream->Read(&m_iDuration);
	pStream->Read(&m_iFreePromotionPick);
	pStream->Read(&m_iGroupSize);
	pStream->Read(&m_iInvisibleType);
	pStream->Read(&m_iRace);
	pStream->Read(&m_iReligion);
	pStream->Read(&m_iResist);
	pStream->Read(&m_iResistModify);
	pStream->Read(&m_iSpellCasterXP);
	pStream->Read(&m_iSpellDamageModify);
	pStream->Read(&m_iTotalDamageTypeCombat);
	pStream->Read(&m_iUnitArtStyleType);
	pStream->Read(GC.getNumBonusInfos(), m_paiBonusAffinity);
	pStream->Read(GC.getNumBonusInfos(), m_paiBonusAffinityAmount);
	pStream->Read(GC.getNumDamageTypeInfos(), m_paiDamageTypeCombat);
	pStream->Read(GC.getNumDamageTypeInfos(), m_paiDamageTypeResist);
//FfH: End Add

	pStream->Read((int*)&m_eOwner);
	pStream->Read((int*)&m_eCapturingPlayer);
	pStream->Read((int*)&m_eUnitType);
	FAssert(NO_UNIT != m_eUnitType);
	m_pUnitInfo = (NO_UNIT != m_eUnitType) ? &GC.getUnitInfo(m_eUnitType) : NULL;
	pStream->Read((int*)&m_eLeaderUnitType);

	pStream->Read((int*)&m_combatUnit.eOwner);
	pStream->Read(&m_combatUnit.iID);
	pStream->Read((int*)&m_transportUnit.eOwner);
	pStream->Read(&m_transportUnit.iID);

	pStream->Read(NUM_DOMAIN_TYPES, m_aiExtraDomainModifier);

	pStream->ReadString(m_szName);
	pStream->ReadString(m_szScriptData);

	pStream->Read(GC.getNumPromotionInfos(), m_pabHasPromotion);

	pStream->Read(GC.getNumTerrainInfos(), m_paiTerrainDoubleMoveCount);
	pStream->Read(GC.getNumFeatureInfos(), m_paiFeatureDoubleMoveCount);
	pStream->Read(GC.getNumTerrainInfos(), m_paiExtraTerrainAttackPercent);
	pStream->Read(GC.getNumTerrainInfos(), m_paiExtraTerrainDefensePercent);
	pStream->Read(GC.getNumFeatureInfos(), m_paiExtraFeatureAttackPercent);
	pStream->Read(GC.getNumFeatureInfos(), m_paiExtraFeatureDefensePercent);
	pStream->Read(GC.getNumUnitCombatInfos(), m_paiExtraUnitCombatModifier);
}


void CvUnit::write(FDataStreamBase* pStream)
{
	uint uiFlag=1;
	pStream->Write(uiFlag);		// flag for expansion

	pStream->Write(m_iID);
	pStream->Write(m_iGroupID);
	pStream->Write(m_iHotKeyNumber);
	pStream->Write(m_iX);
	pStream->Write(m_iY);
	pStream->Write(m_iLastMoveTurn);
	pStream->Write(m_iReconX);
	pStream->Write(m_iReconY);
	pStream->Write(m_iGameTurnCreated);
	pStream->Write(m_iDamage);
	pStream->Write(m_iMoves);
	pStream->Write(m_iExperience);
	pStream->Write(m_iLevel);
	pStream->Write(m_iCargo);
	pStream->Write(m_iCargoCapacity);
	pStream->Write(m_iAttackPlotX);
	pStream->Write(m_iAttackPlotY);
	pStream->Write(m_iCombatTimer);
	pStream->Write(m_iCombatFirstStrikes);
	pStream->Write(m_iCombatDamage);
	pStream->Write(m_iFortifyTurns);
	pStream->Write(m_iBlitzCount);
	pStream->Write(m_iAmphibCount);
	pStream->Write(m_iRiverCount);
/*************************************************************************************************/
/**	New Tag Definitions				05/15/08										Xienwolf	**/
/**																								**/
/**										Write Data to Save Files								**/
/*************************************************************************************************/
	pStream->Write(m_iTerritorialCount);
	pStream->Write(m_iRivalTerritoryExploreCount);
	pStream->Write(m_iRivalTerritoryBlockCount);
	pStream->Write(m_iPillageOnMoveCount);
	pStream->Write(m_iSelfPillageCount);
	pStream->Write(m_iGetCasterXPCount);
	pStream->Write(m_iNonWarWearinessCount);
	pStream->Write(m_iNoMapRevealCount);
	pStream->Write(m_iCannotCaptureCount);
	pStream->Write(m_iCityHappyCount);
	pStream->Write(m_iCityNoHappyCount);
	pStream->Write(m_iNoSupportCount);
	pStream->Write(m_iCanPillageCount);
	pStream->Write(m_iCannotPillageCount);
	pStream->Write(m_iCitySpyCount);
	pStream->Write(m_iStartGoldenAgeCount);
	pStream->Write(m_iNoDefenseBonusCount);
	pStream->Write(m_iMoveImpassableCount);
	pStream->Write(m_iFlatMoveCostCount);
	pStream->Write(m_iIgnoreTerrainCostsCount);
	pStream->Write(m_iAttackNoWarCount);
	pStream->Write(m_iAllowAttacksCount);
	pStream->Write(m_iFirstStrikeVulnerableCount);
	pStream->Write(m_iAllowDefenseBonusesCount);
	pStream->Write(m_iNonAbandonCount);
	pStream->Write(m_iIndependantCount);

	pStream->Write(m_iWorkRateChange);
	pStream->Write(m_iCombatConversionChance);
	pStream->Write(m_iCombatUnitGenerationChance);
	pStream->Write(m_iSlaveGenerationChance);
	pStream->Write(m_iGiftableXP);
	pStream->Write(m_iCombatExtraDuration);
	pStream->Write(m_iDurationPerTurn);
	pStream->Write(m_iChangeDuration);
	pStream->Write(m_bNonTemporary);
	pStream->Write(m_iExtraSupport);
	pStream->Write(m_iChanceMiscast);
	pStream->Write(m_iCombatDmgCap);
	pStream->Write(m_iCombatDmgCapBoost);
	pStream->Write(m_iCollateralLimitCap);
	pStream->Write(m_iCollateralLimitBoost);
	pStream->Write(m_iCollateralTargetsLimit);
	pStream->Write(m_iCollateralExtraTargets);
	pStream->Write(m_iHammerSacrifice);
	pStream->Write(m_iExtraHammerPerPop);
	pStream->Write(m_iFoodSacrifice);
	pStream->Write(m_iPopulationAdd);
	pStream->Write(m_iBeakerSacrifice);
	pStream->Write(m_iExtraBeakerPerPop);
	pStream->Write(m_iGoldSacrifice);
	pStream->Write(m_iExtraGoldPerPop);
	pStream->Write(m_iCultureSacrifice);
	pStream->Write(m_iExtraCulturePerPop);

	pStream->Write(NUM_YIELD_TYPES, m_piYieldFromWin);
	pStream->Write(NUM_YIELD_TYPES, m_piYieldForLoss);
	pStream->Write(NUM_COMMERCE_TYPES, m_piCommerceFromWin);
	pStream->Write(NUM_COMMERCE_TYPES, m_piCommerceForLoss);
/*************************************************************************************************/
/**	New Tag Definitions							END												**/
/*************************************************************************************************/
	pStream->Write(m_iEnemyRouteCount);
	pStream->Write(m_iAlwaysHealCount);
	pStream->Write(m_iHillsDoubleMoveCount);
	pStream->Write(m_iImmuneToFirstStrikesCount);
	pStream->Write(m_iExtraVisibilityRange);
	pStream->Write(m_iExtraMoves);
	pStream->Write(m_iExtraMoveDiscount);
	pStream->Write(m_iExtraAirRange);
	pStream->Write(m_iExtraIntercept);
	pStream->Write(m_iExtraEvasion);
	pStream->Write(m_iExtraFirstStrikes);
	pStream->Write(m_iExtraChanceFirstStrikes);
	pStream->Write(m_iExtraWithdrawal);
	pStream->Write(m_iExtraCollateralDamage);
	pStream->Write(m_iExtraBombardRate);
	pStream->Write(m_iExtraEnemyHeal);
	pStream->Write(m_iExtraNeutralHeal);
	pStream->Write(m_iExtraFriendlyHeal);
	pStream->Write(m_iSameTileHeal);
	pStream->Write(m_iAdjacentTileHeal);
	pStream->Write(m_iExtraCombatPercent);
	pStream->Write(m_iExtraCityAttackPercent);
	pStream->Write(m_iExtraCityDefensePercent);
	pStream->Write(m_iExtraHillsAttackPercent);
	pStream->Write(m_iExtraHillsDefensePercent);
	pStream->Write(m_iRevoltProtection);
	pStream->Write(m_iCollateralDamageProtection);
	pStream->Write(m_iPillageChange);
	pStream->Write(m_iUpgradeDiscount);
	pStream->Write(m_iExperiencePercent);
	pStream->Write(m_iKamikazePercent);
	pStream->Write(m_iBaseCombat);
	pStream->Write(m_eFacingDirection);
	pStream->Write(m_iImmobileTimer);

	pStream->Write(m_bMadeAttack);
	pStream->Write(m_bMadeInterception);
	pStream->Write(m_bPromotionReady);
	pStream->Write(m_bDeathDelay);
	pStream->Write(m_bCombatFocus);
	// m_bInfoBarDirty not saved...
	pStream->Write(m_bBlockading);
	pStream->Write(m_bAirCombat);

//FfH Spell System: Added by Kael 07/23/2007
	pStream->Write(m_bAlive);
	pStream->Write(m_bBoarding);
	pStream->Write(m_bDoubleFortifyBonus);
	pStream->Write(m_bFear);
	pStream->Write(m_bFleeImmortal);
	pStream->Write(m_bFleeWithdrawl);
	pStream->Write(m_bFlying);
	pStream->Write(m_bHasCasted);
	pStream->Write(m_bHiddenNationality);
	pStream->Write(m_bIgnoreBuildingDefense);
	pStream->Write(m_bImmortal);
	pStream->Write(m_bImmuneToCapture);
	pStream->Write(m_bImmuneToFear);
	pStream->Write(m_bImmuneToMagic);
	pStream->Write(m_bOnlyDefensive);
	pStream->Write(m_bTargetWeakestUnit);
	pStream->Write(m_bTargetWeakestUnitCounter);
	pStream->Write(m_bTwincast);
	pStream->Write(m_bWaterWalking);
	pStream->Write(m_iBaseCombatDefense);
	pStream->Write(m_iBetterDefenderThanPercent);
	pStream->Write(m_iCombatHealPercent);
	pStream->Write(m_iCombatLimit);
	pStream->Write(m_iCombatPercentInBorders);
	pStream->Write(m_iCombatPercentGlobalCounter);
	pStream->Write(m_iDelayedSpell);
	pStream->Write(m_iDuration);
	pStream->Write(m_iFreePromotionPick);
	pStream->Write(m_iGroupSize);
	pStream->Write(m_iInvisibleType);
	pStream->Write(m_iRace);
	pStream->Write(m_iReligion);
	pStream->Write(m_iResist);
	pStream->Write(m_iResistModify);
	pStream->Write(m_iSpellCasterXP);
	pStream->Write(m_iSpellDamageModify);
	pStream->Write(m_iTotalDamageTypeCombat);
	pStream->Write(m_iUnitArtStyleType);
	pStream->Write(GC.getNumBonusInfos(), m_paiBonusAffinity);
	pStream->Write(GC.getNumBonusInfos(), m_paiBonusAffinityAmount);
	pStream->Write(GC.getNumDamageTypeInfos(), m_paiDamageTypeCombat);
	pStream->Write(GC.getNumDamageTypeInfos(), m_paiDamageTypeResist);
//FfH: End Add

	pStream->Write(m_eOwner);
	pStream->Write(m_eCapturingPlayer);
	pStream->Write(m_eUnitType);
	pStream->Write(m_eLeaderUnitType);

	pStream->Write(m_combatUnit.eOwner);
	pStream->Write(m_combatUnit.iID);
	pStream->Write(m_transportUnit.eOwner);
	pStream->Write(m_transportUnit.iID);

	pStream->Write(NUM_DOMAIN_TYPES, m_aiExtraDomainModifier);

	pStream->WriteString(m_szName);
	pStream->WriteString(m_szScriptData);

	pStream->Write(GC.getNumPromotionInfos(), m_pabHasPromotion);

	pStream->Write(GC.getNumTerrainInfos(), m_paiTerrainDoubleMoveCount);
	pStream->Write(GC.getNumFeatureInfos(), m_paiFeatureDoubleMoveCount);
	pStream->Write(GC.getNumTerrainInfos(), m_paiExtraTerrainAttackPercent);
	pStream->Write(GC.getNumTerrainInfos(), m_paiExtraTerrainDefensePercent);
	pStream->Write(GC.getNumFeatureInfos(), m_paiExtraFeatureAttackPercent);
	pStream->Write(GC.getNumFeatureInfos(), m_paiExtraFeatureDefensePercent);
	pStream->Write(GC.getNumUnitCombatInfos(), m_paiExtraUnitCombatModifier);
}

// Protected Functions...

bool CvUnit::canAdvance(const CvPlot* pPlot, int iThreshold) const
{
	FAssert(canFight());
	FAssert(!(isAnimal() && pPlot->isCity()));
	FAssert(getDomainType() != DOMAIN_AIR);
	FAssert(getDomainType() != DOMAIN_IMMOBILE);

	if (pPlot->getNumVisibleEnemyDefenders(this) > iThreshold)
	{
		return false;
	}

	if (isNoCapture())
	{
		if (pPlot->isEnemyCity(*this))
		{
			return false;
		}
	}

	return true;
}


void CvUnit::collateralCombat(const CvPlot* pPlot, CvUnit* pSkipUnit)
{
	CLLNode<IDInfo>* pUnitNode;
	CvUnit* pLoopUnit;
	CvUnit* pBestUnit;
	CvWString szBuffer;
	int iCollateralStrength;
	int iTheirStrength;
	int iStrengthFactor;
	int iCollateralDamage;
	int iUnitDamage;
	int iDamageCount;
	int iPossibleTargets;
	int iCount;
	int iValue;
	int iBestValue;
	std::map<CvUnit*, int> mapUnitDamage;
	std::map<CvUnit*, int>::iterator it;

	iCollateralStrength = ((((getDomainType() == DOMAIN_AIR) ? airBaseCombatStr() : baseCombatStr()) * collateralDamage()) / 100);

	if (iCollateralStrength == 0)
	{
		return;
	}

	iPossibleTargets = std::min((pPlot->getNumVisibleEnemyDefenders(this) - 1), collateralDamageMaxUnits());

	pUnitNode = pPlot->headUnitNode();

	while (pUnitNode != NULL)
	{
		pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit != pSkipUnit)
		{
			if (isEnemy(pLoopUnit->getTeam(), pPlot))
			{
				if (!(pLoopUnit->isInvisible(getTeam(), false)))
				{
					if (pLoopUnit->canDefend())
					{
						iValue = (1 + GC.getGameINLINE().getSorenRandNum(10000, "Collateral Damage"));

						iValue *= pLoopUnit->currHitPoints();

						mapUnitDamage[pLoopUnit] = iValue;
					}
				}
			}
		}
	}

	iDamageCount = 0;
	iCount = 0;

	while (iCount < iPossibleTargets)
	{
		iBestValue = 0;
		pBestUnit = NULL;

		for (it = mapUnitDamage.begin(); it != mapUnitDamage.end(); it++)
		{
			if (it->second > iBestValue)
			{
				iBestValue = it->second;
				pBestUnit = it->first;
			}
		}

		if (pBestUnit != NULL)
		{
			mapUnitDamage.erase(pBestUnit);

			if (NO_UNITCOMBAT == getUnitCombatType() || !pBestUnit->getUnitInfo().getUnitCombatCollateralImmune(getUnitCombatType()))
			{
				iTheirStrength = pBestUnit->baseCombatStr();

				iStrengthFactor = ((iCollateralStrength + iTheirStrength + 1) / 2);

				iCollateralDamage = (GC.getDefineINT("COLLATERAL_COMBAT_DAMAGE") * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor);

				iCollateralDamage -= (iCollateralDamage * pBestUnit->getCollateralDamageProtection()) / 100;

				iCollateralDamage = std::max(0, iCollateralDamage);

				int iMaxDamage = std::min(collateralDamageLimit(), (collateralDamageLimit() * (iCollateralStrength + iStrengthFactor)) / (iTheirStrength + iStrengthFactor));
				iUnitDamage = std::max(pBestUnit->getDamage(), std::min(pBestUnit->getDamage() + iCollateralDamage, iMaxDamage));

				if (pBestUnit->getDamage() != iUnitDamage)
				{
					pBestUnit->setDamage(iUnitDamage, getOwnerINLINE());
					iDamageCount++;
				}
			}

			iCount++;
		}
		else
		{
			break;
		}
	}

	if (iDamageCount > 0)
	{
		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_SUFFER_COL_DMG", iDamageCount);
		gDLL->getInterfaceIFace()->addMessage(pSkipUnit->getOwnerINLINE(), (pSkipUnit->getDomainType() != DOMAIN_AIR), GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COLLATERAL", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pSkipUnit->getX_INLINE(), pSkipUnit->getY_INLINE(), true, true);

		szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_INFLICT_COL_DMG", getNameKey(), iDamageCount);
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COLLATERAL", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pSkipUnit->getX_INLINE(), pSkipUnit->getY_INLINE());
	}
}


void CvUnit::flankingStrikeCombat(const CvPlot* pPlot, int iAttackerStrength, int iAttackerFirepower, CvUnit* pSkipUnit)
{
	if (pPlot->isCity(true, pSkipUnit->getTeam()))
	{
		return;
	}

	CLLNode<IDInfo>* pUnitNode = pPlot->headUnitNode();

	int iNumUnitsHit = 0;
	while (NULL != pUnitNode)
	{
		CvUnit* pLoopUnit = ::getUnit(pUnitNode->m_data);
		pUnitNode = pPlot->nextUnitNode(pUnitNode);

		if (pLoopUnit != pSkipUnit)
		{
			if (!pLoopUnit->isDead() && isEnemy(pLoopUnit->getTeam(), pPlot))
			{
				if (!(pLoopUnit->isInvisible(getTeam(), false)))
				{
					if (pLoopUnit->canDefend())
					{
						int iFlankingStrength = m_pUnitInfo->getFlankingStrikeUnitClass(pLoopUnit->getUnitClassType());

						if (iFlankingStrength > 0)
						{
							int iDefenderStrength;
							int iDefenderOdds;
							int iAttackerDamage;
							int iDefenderDamage;

							getDefenderCombatValues(*pLoopUnit, pPlot, iAttackerStrength, iAttackerFirepower, iDefenderOdds, iDefenderStrength, iAttackerDamage, iDefenderDamage);

							if (GC.getGameINLINE().getSorenRandNum(GC.getDefineINT("COMBAT_DIE_SIDES"), "Combat") >= iDefenderOdds)
							{
								pLoopUnit->changeDamage((iFlankingStrength * iDefenderDamage) / 100, getOwnerINLINE());
								++iNumUnitsHit;

								if (pLoopUnit->isDead())
								{
									CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_KILLED_UNIT_BY_FLANKING", getNameKey(), pLoopUnit->getNameKey(), pLoopUnit->getVisualCivAdjective(getTeam()));
									gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
									szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNIT_DIED_BY_FLANKING", pLoopUnit->getNameKey(), getNameKey(), getVisualCivAdjective(pLoopUnit->getTeam()));
									gDLL->getInterfaceIFace()->addMessage(pLoopUnit->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

									pLoopUnit->kill(false);
								}
							}
						}
					}
				}
			}
		}
	}

	if (iNumUnitsHit > 0)
	{
		CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_DAMAGED_UNITS_BY_FLANKING", getNameKey(), iNumUnitsHit);
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitVictoryScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

		if (NULL != pSkipUnit)
		{
			szBuffer = gDLL->getText("TXT_KEY_MISC_YOUR_UNITS_DAMAGED_BY_FLANKING", getNameKey(), iNumUnitsHit);
			gDLL->getInterfaceIFace()->addMessage(pSkipUnit->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, GC.getEraInfo(GC.getGameINLINE().getCurrentEra()).getAudioUnitDefeatScript(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE());
		}
	}
}


// Returns true if we were intercepted...
bool CvUnit::interceptTest(const CvPlot* pPlot)
{
	if (GC.getGameINLINE().getSorenRandNum(100, "Evasion Rand") >= evasionProbability())
	{
		CvUnit* pInterceptor = bestInterceptor(pPlot);

		if (pInterceptor != NULL)
		{
			if (GC.getGameINLINE().getSorenRandNum(100, "Intercept Rand (Air)") < pInterceptor->currInterceptionProbability())
			{
				fightInterceptor(pPlot, false);

				return true;
			}
		}
	}

	return false;
}


CvUnit* CvUnit::airStrikeTarget(const CvPlot* pPlot) const
{
	CvUnit* pDefender;

	pDefender = pPlot->getBestDefender(NO_PLAYER, getOwnerINLINE(), this, true);

	if (pDefender != NULL)
	{
		if (!pDefender->isDead())
		{
			if (pDefender->canDefend())
			{
				return pDefender;
			}
		}
	}

	return NULL;
}


bool CvUnit::canAirStrike(const CvPlot* pPlot) const
{
	if (getDomainType() != DOMAIN_AIR)
	{
		return false;
	}

	if (!canAirAttack())
	{
		return false;
	}

	if (!pPlot->isVisible(getTeam(), false))
	{
		return false;
	}

	if (plotDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) > airRange())
	{
		return false;
	}

	if (airStrikeTarget(pPlot) == NULL)
	{
		return false;
	}

	return true;
}


bool CvUnit::airStrike(CvPlot* pPlot)
{
	if (!canAirStrike(pPlot))
	{
		return false;
	}

	if (interceptTest(pPlot))
	{
		return false;
	}

	CvUnit* pDefender = airStrikeTarget(pPlot);

	FAssert(pDefender != NULL);
	FAssert(pDefender->canDefend());

	setReconPlot(pPlot);

	setMadeAttack(true);
	changeMoves(GC.getMOVE_DENOMINATOR());

	int iDamage = airCombatDamage(pDefender);

	int iUnitDamage = std::max(pDefender->getDamage(), std::min((pDefender->getDamage() + iDamage), airCombatLimit()));

	CvWString szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ARE_ATTACKED_BY_AIR", pDefender->getNameKey(), getNameKey(), -(((iUnitDamage - pDefender->getDamage()) * 100) / pDefender->maxHitPoints()));
	gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_AIR_ATTACK", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pPlot->getX_INLINE(), pPlot->getY_INLINE(), true, true);

	szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ATTACK_BY_AIR", getNameKey(), pDefender->getNameKey(), -(((iUnitDamage - pDefender->getDamage()) * 100) / pDefender->maxHitPoints()));
	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_AIR_ATTACKED", MESSAGE_TYPE_INFO, pDefender->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

	collateralCombat(pPlot, pDefender);

	pDefender->setDamage(iUnitDamage, getOwnerINLINE());

	return true;
}

bool CvUnit::canRangeStrike() const
{
	if (getDomainType() == DOMAIN_AIR)
	{
		return false;
	}

	if (airRange() <= 0)
	{
		return false;
	}

	if (airBaseCombatStr() <= 0)
	{
		return false;
	}

	if (!canFight())
	{
		return false;
	}

	if (isMadeAttack() && !isBlitz())
	{
		return false;
	}

	if (!canMove() && getMoves() > 0)
	{
		return false;
	}

	return true;
}

bool CvUnit::canRangeStrikeAt(const CvPlot* pPlot, int iX, int iY) const
{
	if (!canRangeStrike())
	{
		return false;
	}

	CvPlot* pTargetPlot = GC.getMapINLINE().plotINLINE(iX, iY);

	if (NULL == pTargetPlot)
	{
		return false;
	}

	if (!pPlot->isVisible(getTeam(), false))
	{
		return false;
	}

	if (plotDistance(pPlot->getX_INLINE(), pPlot->getY_INLINE(), pTargetPlot->getX_INLINE(), pTargetPlot->getY_INLINE()) > airRange())
	{
		return false;
	}

	CvUnit* pDefender = airStrikeTarget(pTargetPlot);
	if (NULL == pDefender)
	{
		return false;
	}

	if (!pPlot->canSeePlot(pTargetPlot, getTeam(), airRange(), getFacingDirection(true)))
	{
		return false;
	}

	return true;
}


bool CvUnit::rangeStrike(int iX, int iY)
{
	CvUnit* pDefender;
	CvWString szBuffer;
	int iUnitDamage;
	int iDamage;

	CvPlot* pPlot = GC.getMapINLINE().plot(iX, iY);
	if (NULL == pPlot)
	{
		return false;
	}

	if (!canRangeStrikeAt(pPlot, iX, iY))
	{
		return false;
	}

	pDefender = airStrikeTarget(pPlot);

	FAssert(pDefender != NULL);
	FAssert(pDefender->canDefend());

	if (GC.getDefineINT("RANGED_ATTACKS_USE_MOVES") == 0)
	{
		setMadeAttack(true);
	}
	changeMoves(GC.getMOVE_DENOMINATOR());

	iDamage = rangeCombatDamage(pDefender);

	iUnitDamage = std::max(pDefender->getDamage(), std::min((pDefender->getDamage() + iDamage), airCombatLimit()));

	szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ARE_ATTACKED_BY_AIR", pDefender->getNameKey(), getNameKey(), -(((iUnitDamage - pDefender->getDamage()) * 100) / pDefender->maxHitPoints()));
	//red icon over attacking unit
	gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COMBAT", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), this->getX_INLINE(), this->getY_INLINE(), true, true);
	//white icon over defending unit
	gDLL->getInterfaceIFace()->addMessage(pDefender->getOwnerINLINE(), false, 0, L"", "AS2D_COMBAT", MESSAGE_TYPE_DISPLAY_ONLY, pDefender->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), pDefender->getX_INLINE(), pDefender->getY_INLINE(), true, true);

	szBuffer = gDLL->getText("TXT_KEY_MISC_YOU_ATTACK_BY_AIR", getNameKey(), pDefender->getNameKey(), -(((iUnitDamage - pDefender->getDamage()) * 100) / pDefender->maxHitPoints()));
	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_COMBAT", MESSAGE_TYPE_INFO, pDefender->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pPlot->getX_INLINE(), pPlot->getY_INLINE());

	collateralCombat(pPlot, pDefender);

	//set damage but don't update entity damage visibility
	pDefender->setDamage(iUnitDamage, getOwnerINLINE(), false);

	if (pPlot->isActiveVisible(false))
	{
		// Range strike entity mission
		CvMissionDefinition kDefiniton;
		kDefiniton.setMissionTime(GC.getMissionInfo(MISSION_RANGE_ATTACK).getTime() * gDLL->getSecsPerTurn());
		kDefiniton.setMissionType(MISSION_RANGE_ATTACK);
		kDefiniton.setPlot(pDefender->plot());
		kDefiniton.setUnit(BATTLE_UNIT_ATTACKER, this);
		kDefiniton.setUnit(BATTLE_UNIT_DEFENDER, pDefender);
		gDLL->getEntityIFace()->AddMission(&kDefiniton);

		//delay death
		pDefender->getGroup()->setMissionTimer(GC.getMissionInfo(MISSION_RANGE_ATTACK).getTime());
	}

	return true;
}

//------------------------------------------------------------------------------------------------
// FUNCTION:    CvUnit::planBattle
//! \brief      Determines in general how a battle will progress.
//!
//!				Note that the outcome of the battle is not determined here. This function plans
//!				how many sub-units die and in which 'rounds' of battle.
//! \param      kBattleDefinition The battle definition, which receives the battle plan.
//! \retval     The number of game turns that the battle should be given.
//------------------------------------------------------------------------------------------------
int CvUnit::planBattle( CvBattleDefinition & kBattleDefinition ) const
{
#define BATTLE_TURNS_SETUP 4
#define BATTLE_TURNS_ENDING 4
#define BATTLE_TURNS_MELEE 6
#define BATTLE_TURNS_RANGED 6
#define BATTLE_TURN_RECHECK 4

	int								aiUnitsBegin[BATTLE_UNIT_COUNT];
	int								aiUnitsEnd[BATTLE_UNIT_COUNT];
	int								aiToKillMelee[BATTLE_UNIT_COUNT];
	int								aiToKillRanged[BATTLE_UNIT_COUNT];
	CvBattleRoundVector::iterator	iIterator;
	int								i, j;
	bool							bIsLoser;
	int								iRoundIndex;
	int								iTotalRounds = 0;
	int								iRoundCheck = BATTLE_TURN_RECHECK;

	// Initial conditions
	kBattleDefinition.setNumRangedRounds(0);
	kBattleDefinition.setNumMeleeRounds(0);

	int iFirstStrikesDelta = kBattleDefinition.getFirstStrikes(BATTLE_UNIT_ATTACKER) - kBattleDefinition.getFirstStrikes(BATTLE_UNIT_DEFENDER);
	if (iFirstStrikesDelta > 0) // Attacker first strikes
	{
		int iKills = computeUnitsToDie( kBattleDefinition, true, BATTLE_UNIT_DEFENDER );
		kBattleDefinition.setNumRangedRounds(std::max(iFirstStrikesDelta, iKills / iFirstStrikesDelta));
	}
	else if (iFirstStrikesDelta < 0) // Defender first strikes
	{
		int iKills = computeUnitsToDie( kBattleDefinition, true, BATTLE_UNIT_ATTACKER );
		iFirstStrikesDelta = -iFirstStrikesDelta;
		kBattleDefinition.setNumRangedRounds(std::max(iFirstStrikesDelta, iKills / iFirstStrikesDelta));
	}
	increaseBattleRounds( kBattleDefinition);


	// Keep randomizing until we get something valid
	do
	{
		iRoundCheck++;
		if ( iRoundCheck >= BATTLE_TURN_RECHECK )
		{
			increaseBattleRounds( kBattleDefinition);
			iTotalRounds = kBattleDefinition.getNumRangedRounds() + kBattleDefinition.getNumMeleeRounds();
			iRoundCheck = 0;
		}

		// Make sure to clear the battle plan, we may have to do this again if we can't find a plan that works.
		kBattleDefinition.clearBattleRounds();

		// Create the round list
		CvBattleRound kRound;
		kBattleDefinition.setBattleRound(iTotalRounds, kRound);

		// For the attacker and defender
		for ( i = 0; i < BATTLE_UNIT_COUNT; i++ )
		{
			// Gather some initial information
			BattleUnitTypes unitType = (BattleUnitTypes) i;
			aiUnitsBegin[unitType] = kBattleDefinition.getUnit(unitType)->getSubUnitsAlive(kBattleDefinition.getDamage(unitType, BATTLE_TIME_BEGIN));
			aiToKillRanged[unitType] = computeUnitsToDie( kBattleDefinition, true, unitType);
			aiToKillMelee[unitType] = computeUnitsToDie( kBattleDefinition, false, unitType);
			aiUnitsEnd[unitType] = aiUnitsBegin[unitType] - aiToKillMelee[unitType] - aiToKillRanged[unitType];

			// Make sure that if they aren't dead at the end, they have at least one unit left
			if ( aiUnitsEnd[unitType] == 0 && !kBattleDefinition.getUnit(unitType)->isDead() )
			{
				aiUnitsEnd[unitType]++;
				if ( aiToKillMelee[unitType] > 0 )
				{
					aiToKillMelee[unitType]--;
				}
				else
				{
					aiToKillRanged[unitType]--;
				}
			}

			// If one unit is the loser, make sure that at least one of their units dies in the last round
			if ( aiUnitsEnd[unitType] == 0 )
			{
				kBattleDefinition.getBattleRound(iTotalRounds - 1).addNumKilled(unitType, 1);
				if ( aiToKillMelee[unitType] > 0)
				{
					aiToKillMelee[unitType]--;
				}
				else
				{
					aiToKillRanged[unitType]--;
				}
			}

			// Randomize in which round each death occurs
			bIsLoser = aiUnitsEnd[unitType] == 0;

			// Randomize the ranged deaths
			for ( j = 0; j < aiToKillRanged[unitType]; j++ )
			{
				iRoundIndex = GC.getGameINLINE().getSorenRandNum( range( kBattleDefinition.getNumRangedRounds(), 0, kBattleDefinition.getNumRangedRounds()), "Ranged combat death");
				kBattleDefinition.getBattleRound(iRoundIndex).addNumKilled(unitType, 1);
			}

			// Randomize the melee deaths
			for ( j = 0; j < aiToKillMelee[unitType]; j++ )
			{
				iRoundIndex = GC.getGameINLINE().getSorenRandNum( range( kBattleDefinition.getNumMeleeRounds() - (bIsLoser ? 1 : 2 ), 0, kBattleDefinition.getNumMeleeRounds()), "Melee combat death");
				kBattleDefinition.getBattleRound(kBattleDefinition.getNumRangedRounds() + iRoundIndex).addNumKilled(unitType, 1);
			}

			// Compute alive sums
			int iNumberKilled = 0;
			for(int j=0;j<kBattleDefinition.getNumBattleRounds();j++)
			{
				CvBattleRound &round = kBattleDefinition.getBattleRound(j);
				round.setRangedRound(j < kBattleDefinition.getNumRangedRounds());
				iNumberKilled += round.getNumKilled(unitType);
				round.setNumAlive(unitType, aiUnitsBegin[unitType] - iNumberKilled);
			}
		}

		// Now compute wave sizes
		for(int i=0;i<kBattleDefinition.getNumBattleRounds();i++)
		{
			CvBattleRound &round = kBattleDefinition.getBattleRound(i);
			round.setWaveSize(computeWaveSize(round.isRangedRound(), round.getNumAlive(BATTLE_UNIT_ATTACKER) + round.getNumKilled(BATTLE_UNIT_ATTACKER), round.getNumAlive(BATTLE_UNIT_DEFENDER) + round.getNumKilled(BATTLE_UNIT_DEFENDER)));
		}

		if ( iTotalRounds > 400 )
		{
			kBattleDefinition.setNumMeleeRounds(1);
			kBattleDefinition.setNumRangedRounds(0);
			break;
		}
	}
	while ( !verifyRoundsValid( kBattleDefinition ));

	//add a little extra time for leader to surrender
	bool attackerLeader = false;
	bool defenderLeader = false;
	bool attackerDie = false;
	bool defenderDie = false;
	int lastRound = kBattleDefinition.getNumBattleRounds() - 1;
	if(kBattleDefinition.getUnit(BATTLE_UNIT_ATTACKER)->getLeaderUnitType() != NO_UNIT)
		attackerLeader = true;
	if(kBattleDefinition.getUnit(BATTLE_UNIT_DEFENDER)->getLeaderUnitType() != NO_UNIT)
		defenderLeader = true;
	if(kBattleDefinition.getBattleRound(lastRound).getNumAlive(BATTLE_UNIT_ATTACKER) == 0)
		attackerDie = true;
	if(kBattleDefinition.getBattleRound(lastRound).getNumAlive(BATTLE_UNIT_DEFENDER) == 0)
		defenderDie = true;

	int extraTime = 0;
	if((attackerLeader && attackerDie) || (defenderLeader && defenderDie))
		extraTime = BATTLE_TURNS_MELEE;
	if(gDLL->getEntityIFace()->GetSiegeTower(kBattleDefinition.getUnit(BATTLE_UNIT_ATTACKER)->getUnitEntity()) || gDLL->getEntityIFace()->GetSiegeTower(kBattleDefinition.getUnit(BATTLE_UNIT_DEFENDER)->getUnitEntity()))
		extraTime = BATTLE_TURNS_MELEE;

	return BATTLE_TURNS_SETUP + BATTLE_TURNS_ENDING + kBattleDefinition.getNumMeleeRounds() * BATTLE_TURNS_MELEE + kBattleDefinition.getNumRangedRounds() * BATTLE_TURNS_MELEE + extraTime;
}

//------------------------------------------------------------------------------------------------
// FUNCTION:	CvBattleManager::computeDeadUnits
//! \brief		Computes the number of units dead, for either the ranged or melee portion of combat.
//! \param		kDefinition The battle definition.
//! \param		bRanged true if computing the number of units that die during the ranged portion of combat,
//!					false if computing the number of units that die during the melee portion of combat.
//! \param		iUnit The index of the unit to compute (BATTLE_UNIT_ATTACKER or BATTLE_UNIT_DEFENDER).
//! \retval		The number of units that should die for the given unit in the given portion of combat
//------------------------------------------------------------------------------------------------
int CvUnit::computeUnitsToDie( const CvBattleDefinition & kDefinition, bool bRanged, BattleUnitTypes iUnit ) const
{
	FAssertMsg( iUnit == BATTLE_UNIT_ATTACKER || iUnit == BATTLE_UNIT_DEFENDER, "Invalid unit index");

	BattleTimeTypes iBeginIndex = bRanged ? BATTLE_TIME_BEGIN : BATTLE_TIME_RANGED;
	BattleTimeTypes iEndIndex = bRanged ? BATTLE_TIME_RANGED : BATTLE_TIME_END;
	return kDefinition.getUnit(iUnit)->getSubUnitsAlive(kDefinition.getDamage(iUnit, iBeginIndex)) -
		kDefinition.getUnit(iUnit)->getSubUnitsAlive( kDefinition.getDamage(iUnit, iEndIndex));
}

//------------------------------------------------------------------------------------------------
// FUNCTION:    CvUnit::verifyRoundsValid
//! \brief      Verifies that all rounds in the battle plan are valid
//! \param      vctBattlePlan The battle plan
//! \retval     true if the battle plan (seems) valid, false otherwise
//------------------------------------------------------------------------------------------------
bool CvUnit::verifyRoundsValid( const CvBattleDefinition & battleDefinition ) const
{
	for(int i=0;i<battleDefinition.getNumBattleRounds();i++)
	{
		if(!battleDefinition.getBattleRound(i).isValid())
			return false;
	}
	return true;
}

//------------------------------------------------------------------------------------------------
// FUNCTION:    CvUnit::increaseBattleRounds
//! \brief      Increases the number of rounds in the battle.
//! \param      kBattleDefinition The definition of the battle
//------------------------------------------------------------------------------------------------
void CvUnit::increaseBattleRounds( CvBattleDefinition & kBattleDefinition ) const
{
	if ( kBattleDefinition.getUnit(BATTLE_UNIT_ATTACKER)->isRanged() && kBattleDefinition.getUnit(BATTLE_UNIT_DEFENDER)->isRanged())
	{
		kBattleDefinition.addNumRangedRounds(1);
	}
	else
	{
		kBattleDefinition.addNumMeleeRounds(1);
	}
}

//------------------------------------------------------------------------------------------------
// FUNCTION:    CvUnit::computeWaveSize
//! \brief      Computes the wave size for the round.
//! \param      bRangedRound true if the round is a ranged round
//! \param		iAttackerMax The maximum number of attackers that can participate in a wave (alive)
//! \param		iDefenderMax The maximum number of Defenders that can participate in a wave (alive)
//! \retval     The desired wave size for the given parameters
//------------------------------------------------------------------------------------------------
int CvUnit::computeWaveSize( bool bRangedRound, int iAttackerMax, int iDefenderMax ) const
{
	FAssertMsg( getCombatUnit() != NULL, "You must be fighting somebody!" );
	int aiDesiredSize[BATTLE_UNIT_COUNT];
	if ( bRangedRound )
	{
		aiDesiredSize[BATTLE_UNIT_ATTACKER] = getUnitInfo().getRangedWaveSize();
		aiDesiredSize[BATTLE_UNIT_DEFENDER] = getCombatUnit()->getUnitInfo().getRangedWaveSize();
	}
	else
	{
		aiDesiredSize[BATTLE_UNIT_ATTACKER] = getUnitInfo().getMeleeWaveSize();
		aiDesiredSize[BATTLE_UNIT_DEFENDER] = getCombatUnit()->getUnitInfo().getMeleeWaveSize();
	}

	aiDesiredSize[BATTLE_UNIT_DEFENDER] = aiDesiredSize[BATTLE_UNIT_DEFENDER] <= 0 ? iDefenderMax : aiDesiredSize[BATTLE_UNIT_DEFENDER];
	aiDesiredSize[BATTLE_UNIT_ATTACKER] = aiDesiredSize[BATTLE_UNIT_ATTACKER] <= 0 ? iDefenderMax : aiDesiredSize[BATTLE_UNIT_ATTACKER];
	return std::min( std::min( aiDesiredSize[BATTLE_UNIT_ATTACKER], iAttackerMax ), std::min( aiDesiredSize[BATTLE_UNIT_DEFENDER],
		iDefenderMax) );
}

bool CvUnit::isTargetOf(const CvUnit& attacker) const
{
	CvUnitInfo& attackerInfo = attacker.getUnitInfo();
	CvUnitInfo& ourInfo = getUnitInfo();

	if (!plot()->isCity(true, getTeam()))
	{
		if (NO_UNITCLASS != getUnitClassType() && attackerInfo.getTargetUnitClass(getUnitClassType()))
		{
			return true;
		}

		if (NO_UNITCOMBAT != getUnitCombatType() && attackerInfo.getTargetUnitCombat(getUnitCombatType()))
		{
			return true;
		}
	}

	if (NO_UNITCLASS != attackerInfo.getUnitClassType() && ourInfo.getDefenderUnitClass(attackerInfo.getUnitClassType()))
	{
		return true;
	}

	if (NO_UNITCOMBAT != attackerInfo.getUnitCombatType() && ourInfo.getDefenderUnitCombat(attackerInfo.getUnitCombatType()))
	{
		return true;
	}

	return false;
}

bool CvUnit::isEnemy(TeamTypes eTeam, const CvPlot* pPlot) const
{
	if (NULL == pPlot)
	{
		pPlot = plot();
	}

//FfH: Added by Kael 10/26/2007 (to prevent spinlocks when always hostile units attack barbarian allied teams)
    if (isAlwaysHostile(pPlot))
    {
        if (getTeam() != eTeam)
        {
            return true;
        }
    }
//FfH: End Add

	return (atWar(GET_PLAYER(getCombatOwner(eTeam, pPlot)).getTeam(), eTeam));
}

bool CvUnit::isPotentialEnemy(TeamTypes eTeam, const CvPlot* pPlot) const
{
	if (NULL == pPlot)
	{
		pPlot = plot();
	}

	return (::isPotentialEnemy(GET_PLAYER(getCombatOwner(eTeam, pPlot)).getTeam(), eTeam));
}

bool CvUnit::isSuicide() const
{
	return (m_pUnitInfo->isSuicide() || getKamikazePercent() != 0);
}

int CvUnit::getDropRange() const
{
	return (m_pUnitInfo->getDropRange());
}

void CvUnit::getDefenderCombatValues(CvUnit& kDefender, const CvPlot* pPlot, int iOurStrength, int iOurFirepower, int& iTheirOdds, int& iTheirStrength, int& iOurDamage, int& iTheirDamage, CombatDetails* pTheirDetails) const
{
	iTheirStrength = kDefender.currCombatStr(pPlot, this, pTheirDetails);
	int iTheirFirepower = kDefender.currFirepower(pPlot, this);

	FAssert((iOurStrength + iTheirStrength) > 0);
	FAssert((iOurFirepower + iTheirFirepower) > 0);

	iTheirOdds = ((GC.getDefineINT("COMBAT_DIE_SIDES") * iTheirStrength) / (iOurStrength + iTheirStrength));

	if (kDefender.isBarbarian())
	{
		if (GET_PLAYER(getOwnerINLINE()).getWinsVsBarbs() < GC.getHandicapInfo(GET_PLAYER(getOwnerINLINE()).getHandicapType()).getFreeWinsVsBarbs())
		{
			iTheirOdds = std::min((10 * GC.getDefineINT("COMBAT_DIE_SIDES")) / 100, iTheirOdds);
		}
	}
	if (isBarbarian())
	{
		if (GET_PLAYER(kDefender.getOwnerINLINE()).getWinsVsBarbs() < GC.getHandicapInfo(GET_PLAYER(kDefender.getOwnerINLINE()).getHandicapType()).getFreeWinsVsBarbs())
		{
			iTheirOdds =  std::max((90 * GC.getDefineINT("COMBAT_DIE_SIDES")) / 100, iTheirOdds);
		}
	}

	int iStrengthFactor = ((iOurFirepower + iTheirFirepower + 1) / 2);

	iOurDamage = std::max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (iTheirFirepower + iStrengthFactor)) / (iOurFirepower + iStrengthFactor)));
	iTheirDamage = std::max(1, ((GC.getDefineINT("COMBAT_DAMAGE") * (iOurFirepower + iStrengthFactor)) / (iTheirFirepower + iStrengthFactor)));
}

int CvUnit::getTriggerValue(EventTriggerTypes eTrigger, const CvPlot* pPlot, bool bCheckPlot) const
{
	CvEventTriggerInfo& kTrigger = GC.getEventTriggerInfo(eTrigger);
	if (kTrigger.getNumUnits() <= 0)
	{
		return MIN_INT;
	}

	if (!isEmpty(kTrigger.getPythonCanDoUnit()))
	{
		long lResult;

		CyArgsList argsList;
		argsList.add(eTrigger);
		argsList.add(getOwnerINLINE());
		argsList.add(getID());

		gDLL->getPythonIFace()->callFunction(PYRandomEventModule, kTrigger.getPythonCanDoUnit(), argsList.makeFunctionArgs(), &lResult);

		if (0 == lResult)
		{
			return MIN_INT;
		}
	}

	if (kTrigger.getNumUnitsRequired() > 0)
	{
		bool bFoundValid = false;
		for (int i = 0; i < kTrigger.getNumUnitsRequired(); ++i)
		{
			if (getUnitClassType() == kTrigger.getUnitRequired(i))
			{
				bFoundValid = true;
				break;
			}
		}

		if (!bFoundValid)
		{
			return MIN_INT;
		}
	}

	if (bCheckPlot)
	{
		if (kTrigger.isUnitsOnPlot())
		{
			if (!plot()->canTrigger(eTrigger, getOwnerINLINE()))
			{
				return MIN_INT;
			}
		}
	}

	int iValue = 0;

	if (0 == getDamage() && kTrigger.getUnitDamagedWeight() > 0)
	{
		return MIN_INT;
	}

	iValue += getDamage() * kTrigger.getUnitDamagedWeight();

	iValue += getExperience() * kTrigger.getUnitExperienceWeight();

	if (NULL != pPlot)
	{
		iValue += plotDistance(getX_INLINE(), getY_INLINE(), pPlot->getX_INLINE(), pPlot->getY_INLINE()) * kTrigger.getUnitDistanceWeight();
	}

	return iValue;
}

bool CvUnit::canApplyEvent(EventTypes eEvent) const
{
	CvEventInfo& kEvent = GC.getEventInfo(eEvent);

	if (0 != kEvent.getUnitExperience())
	{
		if (!canAcquirePromotionAny())
		{
			return false;
		}
	}

	if (NO_PROMOTION != kEvent.getUnitPromotion())
	{

//FfH: Modified by Kael 10/29/2007
//		if (!canAcquirePromotion((PromotionTypes)kEvent.getUnitPromotion()))
//		{
//			return false;
//		}
        if (isHasPromotion((PromotionTypes)kEvent.getUnitPromotion()))
        {
            return false;
        }
//FfH: End Modify

	}

	if (kEvent.getUnitImmobileTurns() > 0)
	{
		if (!canAttack())
		{
			return false;
		}
	}

	return true;
}

void CvUnit::applyEvent(EventTypes eEvent)
{
	if (!canApplyEvent(eEvent))
	{
		return;
	}

	CvEventInfo& kEvent = GC.getEventInfo(eEvent);

	if (0 != kEvent.getUnitExperience())
	{
		setDamage(0);
		changeExperience(kEvent.getUnitExperience());
	}

	if (NO_PROMOTION != kEvent.getUnitPromotion())
	{
		setHasPromotion((PromotionTypes)kEvent.getUnitPromotion(), true);
	}

	if (kEvent.getUnitImmobileTurns() > 0)
	{
		changeImmobileTimer(kEvent.getUnitImmobileTurns());
		CvWString szText = gDLL->getText("TXT_KEY_EVENT_UNIT_IMMOBILE", getNameKey(), kEvent.getUnitImmobileTurns());
		gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szText, "AS2D_UNITGIFTED", MESSAGE_TYPE_INFO, getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_UNIT_TEXT"), getX_INLINE(), getY_INLINE(), true, true);
	}

	CvWString szNameKey(kEvent.getUnitNameKey());

	if (!szNameKey.empty())
	{
		setName(gDLL->getText(kEvent.getUnitNameKey()));
	}

	if (kEvent.isDisbandUnit())
	{
		kill(false);
	}
}

const CvArtInfoUnit* CvUnit::getArtInfo(int i, EraTypes eEra) const
{

//FfH: Added by Kael 10/26/2007
    if (getUnitArtStyleType() != NO_UNIT_ARTSTYLE)
    {
        return m_pUnitInfo->getArtInfo(i, eEra, (UnitArtStyleTypes) getUnitArtStyleType());
    }
//FfH: End Add

	return m_pUnitInfo->getArtInfo(i, eEra, (UnitArtStyleTypes) GC.getCivilizationInfo(GET_PLAYER(getOwnerINLINE()).getCivilizationType()).getUnitArtStyleType());
}

const TCHAR* CvUnit::getButton() const
{
	const CvArtInfoUnit* pArtInfo = getArtInfo(0, GET_PLAYER(getOwnerINLINE()).getCurrentEra());

	if (NULL != pArtInfo)
	{
		return pArtInfo->getButton();
	}

	return m_pUnitInfo->getButton();
}


bool CvUnit::isAlwaysHostile(const CvPlot* pPlot) const
{

/*************************************************************************************************/
/**	Hostility (PromotionInfos)		05/15/08										Xienwolf	**/
/**	Modification to Hidden Nationality so that a Unit is not considered HN while inside a City	**/
/**							as well as inclusion of my new Promotion Tag						**/
/*************************************************************************************************/
/**								---- Start Original Code ----
//FfH: Added by Kael 09/15/2007
    if (isHiddenNationality())
    {
        return true;
    }
//FfH: End Add

	if (!m_pUnitInfo->isAlwaysHostile())
								----  End Original Code  ----									**/
	if (!(m_pUnitInfo->isAlwaysHostile() || isHiddenNationality() || isAttackNoWar()))
/*************************************************************************************************/
/**	Hostility (PromotionInfos)					END												**/
/*************************************************************************************************/
    {
		return false;
	}

	if (NULL != pPlot && pPlot->isCity(true, getTeam()))
	{
		return false;
	}

	return true;
}

bool CvUnit::verifyStackValid()
{
	if (plot()->isVisibleEnemyUnit(this))
	{
		return jumpToNearestValidPlot();
	}

	return true;
}


// Private Functions...

//check if quick combat
bool CvUnit::isCombatVisible(const CvUnit* pDefender) const
{
	bool bVisible = false;

	if (!m_pUnitInfo->isQuickCombat())
	{
		if (NULL == pDefender || !pDefender->getUnitInfo().isQuickCombat())
		{
			if (isHuman())
			{
				if (!GET_PLAYER(getOwnerINLINE()).isOption(PLAYEROPTION_QUICK_ATTACK))
				{
					bVisible = true;
				}
			}
			else if (NULL != pDefender && pDefender->isHuman())
			{
				if (!GET_PLAYER(pDefender->getOwnerINLINE()).isOption(PLAYEROPTION_QUICK_DEFENSE))
				{
					bVisible = true;
				}
			}
		}
	}

	return bVisible;
}

//WH: Ploeperpengel as per ELM add Animosity 12/08/06
//animosityAttack()
//will force a unit to attack a friendly square, or charge a nearby enemy unit
void CvUnit::animosityAttack(CvPlot* pCurrPlot, CvPlot* pPlot, CvUnit* pTargetUnit, bool bShowEm, bool bQuick)
{
    int iPathTurns;

    if (bShowEm)
    {
        if (generatePath(pPlot, 0, true, &iPathTurns))
        {
            pPlot = getPathEndTurnPlot();
        }
    }

    FAssert(canMoveInto(pPlot, true, false, true));
    FAssert(getCombatTimer() == 0);

    setAttackPlot(pPlot, false);
    //call updatecombat with animosity TRUE if it is a Get'em charge
    if (bShowEm)
    {
        updateCombat(bQuick, false, pTargetUnit);
    }
    else
    {
        updateCombat(bQuick, true, pTargetUnit);
    }

}
//WH: End Add

//WH: added by Ploeperpengel 04/23/2008---- BEGIN InfluenceDrivenWar ---by Moctezuma-----

// unit influences combat area after victory 
// returns influence % in defended plot
float CvUnit::doVictoryInfluence(CvUnit* pLoserUnit, bool bAttacking, bool bWithdrawal)
{
	if (GC.getDefineINT("IDW_NO_BARBARIAN_INFLUENCE"))
	{
		if (isBarbarian() || pLoserUnit->isBarbarian())
		{
			return 0.0f;
		}
	}
	if (GC.getDefineINT("IDW_NO_NAVAL_INFLUENCE"))
	{
		if (DOMAIN_SEA == getDomainType())
		{
			return 0.0f;
		}
	}

	CvPlot* pWinnerPlot = plot();
	CvPlot* pLoserPlot = pLoserUnit->plot();
	CvPlot* pDefenderPlot = NULL;
	if (!bAttacking)
	{
		pDefenderPlot = pWinnerPlot;
	}
	else
	{
		pDefenderPlot = pLoserPlot;
	}
	int iWinnerCultureBefore = pDefenderPlot->getCulture(getOwnerINLINE()); //used later for influence %

	float fWinnerPlotMultiplier = 1.0f; // by default: same influence in WinnerPlot and LoserPlot
	if (GC.getDefineFLOAT("IDW_WINNER_PLOT_MULTIPLIER"))
		fWinnerPlotMultiplier = GC.getDefineFLOAT("IDW_WINNER_PLOT_MULTIPLIER");

	float fLoserPlotMultiplier = 1.0f; // by default: same influence in WinnerPlot and LoserPlot
	if (GC.getDefineFLOAT("IDW_LOSER_PLOT_MULTIPLIER"))
		fLoserPlotMultiplier = GC.getDefineFLOAT("IDW_LOSER_PLOT_MULTIPLIER");

	float bWithdrawalMultiplier = 0.5f;
	if (bWithdrawal)
	{
		fWinnerPlotMultiplier *= bWithdrawalMultiplier;
		fLoserPlotMultiplier *= bWithdrawalMultiplier;
	}

	if (pLoserPlot->isEnemyCity(*this)) // city combat 
	{         	
		if (pLoserPlot->getNumVisibleEnemyDefenders(this) > 1)
		{
			// if there are still some city defenders ->
			// we use same influence rules as for field combat
			influencePlots(pLoserPlot, pLoserUnit->getOwnerINLINE(), fLoserPlotMultiplier);
			influencePlots(pWinnerPlot, pLoserUnit->getOwnerINLINE(), fWinnerPlotMultiplier);			
		}		
		else // last defender is dead
		{			
			float fNoCityDefenderMultiplier = 2.5; // default: 250%
			if (GC.getDefineFLOAT("IDW_NO_CITY_DEFENDER_MULTIPLIER"))
				fNoCityDefenderMultiplier = GC.getDefineFLOAT("IDW_NO_CITY_DEFENDER_MULTIPLIER");

			// last city defender is dead -> influence is increased
			influencePlots(pLoserPlot, pLoserUnit->getOwnerINLINE(), fLoserPlotMultiplier * fNoCityDefenderMultiplier);
			influencePlots(pWinnerPlot, pLoserUnit->getOwnerINLINE(), fWinnerPlotMultiplier * fNoCityDefenderMultiplier);

			if (GC.getDefineINT("IDW_EMERGENCY_DRAFT_ENABLED"))
			{
				int iDefenderCulture = pLoserPlot->getCulture(pLoserUnit->getOwnerINLINE());
				int iAttackerCulture = pLoserPlot->getCulture(getOwnerINLINE());
				
				if (iDefenderCulture >= iAttackerCulture)
				{
					// if defender culture in city's central tile is still higher then atacker culture 
					// -> city is not captured yet but emergency militia is drafted
					pLoserPlot->getPlotCity()->emergencyConscript();
					
					// calculate city resistence % (to be displayed in game log)
					float fResistence = ((iDefenderCulture-iAttackerCulture)*100.0f)/(2*pDefenderPlot->countTotalCulture());

					CvWString szBuffer;
					szBuffer.Format(L"City militia has emerged! Resistance: %.1f%%", fResistence);	
					gDLL->getInterfaceIFace()->addMessage(pLoserUnit->getOwnerINLINE(), false, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_UNIT_BUILD_UNIT", MESSAGE_TYPE_INFO, GC.getUnitInfo(getUnitType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), pLoserPlot->getX_INLINE(), pLoserPlot->getY_INLINE(), true, true);
					gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_UNIT_BUILD_UNIT", MESSAGE_TYPE_INFO, GC.getUnitInfo(getUnitType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pLoserPlot->getX_INLINE(), pLoserPlot->getY_INLINE());

				}
			}
		}
	}
	else // field combat
	{				
		if (!pLoserUnit->canDefend()) 
		{
			// no influence from worker capture
			return 0.0f;
		}

		if (pLoserPlot->getImprovementType() != NO_IMPROVEMENT 
			&& GC.getImprovementInfo(pLoserPlot->getImprovementType()).getDefenseModifier() > 0
			&& pLoserPlot->getNumVisibleEnemyDefenders(this) > 1)
		{		
			// fort captured
			float fFortCaptureMultiplier = 2.0f; // default: 200%
			if (GC.getDefineFLOAT("IDW_FORT_CAPTURE_MULTIPLIER"))
				fFortCaptureMultiplier = GC.getDefineFLOAT("IDW_FORT_CAPTURE_MULTIPLIER");

			// influence is increased
			influencePlots(pLoserPlot, pLoserUnit->getOwnerINLINE(), fLoserPlotMultiplier * fFortCaptureMultiplier);
			influencePlots(pWinnerPlot, pLoserUnit->getOwnerINLINE(), fWinnerPlotMultiplier * fFortCaptureMultiplier);

		}
		else
		{			
			influencePlots(pLoserPlot, pLoserUnit->getOwnerINLINE(), fLoserPlotMultiplier);
			influencePlots(pWinnerPlot, pLoserUnit->getOwnerINLINE(), fWinnerPlotMultiplier);
		}
	}

	// calculate influence % in defended plot (to be displayed in game log)
    
	int iWinnerCultureAfter = pDefenderPlot->getCulture(getOwnerINLINE());
	int iTotalCulture = pDefenderPlot->countTotalCulture();
	float fInfluenceRatio = 0.0f;
	if (iTotalCulture > 0)
	{
		fInfluenceRatio = ((iWinnerCultureAfter-iWinnerCultureBefore)*100.0f)/iTotalCulture;	
	}
    return fInfluenceRatio;
}

// unit influences given plot and surounding area i.e. transfers culture from target civ to unit's owner
void CvUnit::influencePlots(CvPlot* pCentralPlot, PlayerTypes eTargetPlayer, float fLocationMultiplier)
{
	float fBaseCombatInfluence = 4.0f;    
	if (GC.getDefineFLOAT("IDW_BASE_COMBAT_INFLUENCE"))
        fBaseCombatInfluence = GC.getDefineFLOAT("IDW_BASE_COMBAT_INFLUENCE");

	// calculate base multiplier used for all plots
	float fGameSpeedMultiplier = (float) GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
	fGameSpeedMultiplier /= 100;
	fGameSpeedMultiplier *= GC.getEraInfo(GC.getGameINLINE().getStartEra()).getConstructPercent();
	fGameSpeedMultiplier /= 100;
	fGameSpeedMultiplier = sqrt(fGameSpeedMultiplier);

	float fExperienceFactor = 0.01f;  // default: each point of experience increases influence by 1%
	if (GC.getDefineFLOAT("IDW_EXPERIENCE_FACTOR"))
        fExperienceFactor = GC.getDefineFLOAT("IDW_EXPERIENCE_FACTOR");
	float fExperienceMultiplier = 1.0f + (getExperience() * 0.01f);

	float fWarlordMultiplier = 1.0; 
	if (NO_UNIT != getLeaderUnitType()) // warlord is here
	{
		fWarlordMultiplier = 1.5; // default: +50% 
		if (GC.getDefineFLOAT("IDW_WARLORD_MULTIPLIER"))
			fWarlordMultiplier = GC.getDefineFLOAT("IDW_WARLORD_MULTIPLIER");
	}

	float fBaseMultiplier = fBaseCombatInfluence * fGameSpeedMultiplier * fLocationMultiplier * fExperienceMultiplier * fWarlordMultiplier;
	if (fBaseMultiplier <= 0.0f)
		return;

	// get influence radius
	int iInfluenceRadius = 2; // default: like 2square city workable radius
	if (GC.getDefineINT("IDW_INFLUENCE_RADIUS"))
		iInfluenceRadius = GC.getDefineINT("IDW_INFLUENCE_RADIUS");
	if (iInfluenceRadius < 0)
		return;

	float fPlotDistanceFactor = 0.2f; // default: influence decreases by 20% with plot distance
	if (GC.getDefineFLOAT("IDW_PLOT_DISTANCE_FACTOR"))
        fPlotDistanceFactor = GC.getDefineFLOAT("IDW_PLOT_DISTANCE_FACTOR");

//	CvWString szBuffer;
//	szBuffer.Format(L"Factors: %.1f, %.1f, %.1f, %.1f, %.1f, %.1f, %.3f, %d", fBaseCombatInfluence, fLocationMultiplier, fGameSpeedMultiplier, fPlotDistanceFactor, fExperienceMultiplier, fWarlordMultiplier, fBaseMultiplier, iInfluenceRadius);	
//	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_UNIT_BUILD_UNIT", MESSAGE_TYPE_INFO, GC.getUnitInfo(getUnitType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), pCentralPlot->getX_INLINE(), pCentralPlot->getY_INLINE());

	for (int iDX = -iInfluenceRadius; iDX <= iInfluenceRadius; iDX++)
	{
		for (int iDY = -iInfluenceRadius; iDY <= iInfluenceRadius; iDY++)
		{
			int iDistance = plotDistance(0, 0, iDX, iDY);

			if (iDistance <= iInfluenceRadius)
			{
				CvPlot* pLoopPlot = plotXY(pCentralPlot->getX_INLINE(), pCentralPlot->getY_INLINE(), iDX, iDY);

				if (pLoopPlot != NULL)
				{	
					// calculate distance multiplier for current plot
					float fDistanceMultiplier = 0.5f+0.5f*fPlotDistanceFactor-fPlotDistanceFactor*iDistance;
					if (fDistanceMultiplier <= 0.0f)
						continue;
					int iTargetCulture = pLoopPlot->getCulture(eTargetPlayer);					
					if (iTargetCulture <= 0)
						continue;		
					int iCultureTransfer = int (fBaseMultiplier * fDistanceMultiplier * sqrt((float) iTargetCulture));
					if (iTargetCulture < iCultureTransfer)
					{
						// cannot transfer more culture than remaining target culure
						iCultureTransfer = iTargetCulture;
					}
					if (iCultureTransfer == 0 && iTargetCulture > 0)
					{
						// always at least 1 point of culture must be transfered
						// othervise we may have the problems with capturing of very low culture cities. 
						iCultureTransfer = 1; 
					}

					if (iCultureTransfer > 0)
					{
						// target player's culture in plot is lowered
						pLoopPlot->changeCulture(eTargetPlayer, -iCultureTransfer, false);
						// owners's culture in plot is raised
						pLoopPlot->changeCulture(getOwnerINLINE(), iCultureTransfer, true);
					}
				}	
			}
		}
	}		
}


// unit influences current tile via pillaging 
// returns influence % in current plot
float CvUnit::doPillageInfluence()
{
	if (isBarbarian() && GC.getDefineINT("IDW_NO_BARBARIAN_INFLUENCE"))
	{
		return 0.0f;
	}
	if ((DOMAIN_SEA == getDomainType()) && GC.getDefineINT("IDW_NO_NAVAL_INFLUENCE"))
	{
		return 0.0f;
	}
	
	CvPlot* pPlot = plot();
	if (pPlot == NULL)
	{
		//should not happen
		return 0.0f;	
	}

	int iOurCultureBefore = pPlot->getCulture(getOwnerINLINE()); //used later for influence %

	float fBasePillageInfluence = 2.0f;    
	if (GC.getDefineFLOAT("IDW_BASE_PILLAGE_INFLUENCE"))
        fBasePillageInfluence = GC.getDefineFLOAT("IDW_BASE_PILLAGE_INFLUENCE");

	float fGameSpeedMultiplier = (float) GC.getGameSpeedInfo(GC.getGameINLINE().getGameSpeedType()).getConstructPercent();
	fGameSpeedMultiplier /= 100;
	fGameSpeedMultiplier *= GC.getEraInfo(GC.getGameINLINE().getStartEra()).getConstructPercent();
	fGameSpeedMultiplier /= 100;
	fGameSpeedMultiplier = sqrt(fGameSpeedMultiplier);

	PlayerTypes eTargetPlayer = pPlot->getOwner();
	int iTargetCulture = pPlot->getCulture(eTargetPlayer);
	if (iTargetCulture <= 0)
	{
		//should not happen
		return 0.0f;		
	}
	int iCultureTransfer = int (fBasePillageInfluence * fGameSpeedMultiplier * sqrt((float) iTargetCulture));
	if (iTargetCulture < iCultureTransfer)
	{
		// cannot transfer more culture than remaining target culure
		iCultureTransfer = iTargetCulture;
	}

	// target player's culture in plot is lowered
	pPlot->changeCulture(eTargetPlayer, -iCultureTransfer, false);
	// owners's culture in plot is raised
	pPlot->changeCulture(getOwnerINLINE(), iCultureTransfer, true);

	// calculate influence % in pillaged plot (to be displayed in game log)
    int iOurCultureAfter = pPlot->getCulture(getOwnerINLINE());
	float fInfluenceRatio = ((iOurCultureAfter-iOurCultureBefore)*100.0f)/pPlot->countTotalCulture();	
 
//	CvWString szBuffer;
//	szBuffer.Format(L"Factors: %.1f, %.1f, %d, Result: %.3f, ", fGameSpeedMultiplier, fBasePillageInfluence, iTargetCulture, fInfluenceRatio);	
//	gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer, "AS2D_UNIT_BUILD_UNIT", MESSAGE_TYPE_INFO, GC.getUnitInfo(getUnitType()).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_RED"), plot()->getX_INLINE(), plot()->getY_INLINE());

	return fInfluenceRatio;
}

// ------ END InfluenceDrivenWar ---------------------------------

/*************************************************************************************************/
/**	Food from Animals				01/04/08			Written: DomPedroII	Imported: Xienwolf	**/
/**																								**/
/**	Determines available Yields & Commerces from Defeated Units and selects which to recieve	**/
/*************************************************************************************************/
void CvUnit::salvage(CvUnit* pDeadUnit)
{
    CvWString szBuffer;
    bool bValid;
    int iI;
    int iCount = 0;
    int iRoll;
    int iYield;
    int iCommerce;
    int iCommerceVariable;
    int iTotalCommerce;
    CvCity* pNearestCity;

    pNearestCity = GC.getMapINLINE().findCity(getX_INLINE(), getY_INLINE(), getOwnerINLINE(), NO_TEAM, true, false);
    if (pNearestCity != NULL)
    {
        for (iI = 0; iI < NUM_YIELD_TYPES; iI++)
        {
            if ((pDeadUnit->getYieldForLoss(iI) + GET_PLAYER(getOwnerINLINE()).getBaseYieldFromUnit((YieldTypes)iI) + getYieldFromWin(iI)) != 0)
            {
                iYield = (pDeadUnit->getYieldForLoss(iI) + GET_PLAYER(getOwnerINLINE()).getBaseYieldFromUnit((YieldTypes)iI) + getYieldFromWin(iI));
                iYield *= std::max(0,(GET_PLAYER(getOwnerINLINE()).getYieldFromUnitModifier((YieldTypes)iI) + 100));
                iYield /= 100;

                switch ((YieldTypes)iI)
                {
                case YIELD_FOOD:
                    pNearestCity->changeFood(iYield);
                    break;

                case YIELD_PRODUCTION:
                    pNearestCity->changeProduction(iYield);
                    break;
                }
                    szBuffer = gDLL->getText("TXT_KEY_MISC_YIELD_FROM_UNIT", getNameKey(), iYield, GC.getYieldInfo((YieldTypes)iI).getChar(), pNearestCity->getNameKey());
                    gDLL->getInterfaceIFace()->addMessage(pNearestCity->getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer,  ARTFILEMGR.getInterfaceArtInfo("WORLDBUILDER_CITY_EDIT")->getPath(), MESSAGE_TYPE_INFO, NULL, (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), pDeadUnit->getX_INLINE(), pDeadUnit->getY_INLINE(), true, true);
            }
        }
    }

    CommerceTypes eCommerce;
    std::vector<TechTypes> aeAvailableTechs;
    std::vector<CommerceTypes> aeValidCommerces;
    TechTypes eTempTech;
    TechTypes eRewardTech;

    for (iI = 0; iI < NUM_COMMERCE_TYPES; iI++)
    {
        int iJ;
        eCommerce = ((CommerceTypes)iI);
        bValid = true;
        if ((pDeadUnit->getCommerceForLoss(iI) + GET_PLAYER(getOwnerINLINE()).getBaseCommerceFromUnit(eCommerce) + getCommerceFromWin(eCommerce)) > 0)
        {
            if (eCommerce == COMMERCE_RESEARCH)
            {
                eTempTech = ((TechTypes)GC.getUnitInfo(pDeadUnit->getUnitType()).getPrereqAndTech());

                if (eTempTech != NO_TECH)
                {
//                    if (GET_PLAYER(getOwnerINLINE()).canResearch(eTempTech, true) && GET_TEAM(GET_PLAYER(pDeadUnit->getOwnerINLINE()).getTeam()).isHasTech(eTempTech))
                    if (!GET_TEAM(GET_PLAYER(getOwnerINLINE()).getTeam()).isHasTech(eTempTech))
                    {
                        if (!GC.getTechInfo(eTempTech).isDisable())
                        {
                            aeAvailableTechs.push_back(eTempTech);
                        }
                    }
                }

                for (iJ = 0; iJ < GC.getNUM_UNIT_AND_TECH_PREREQS(); iJ++)
                {
                    eTempTech = ((TechTypes)GC.getUnitInfo(pDeadUnit->getUnitType()).getPrereqAndTechs(iJ));
                    if (eTempTech != NO_TECH)
                    {
//                        if (GET_PLAYER(getOwnerINLINE()).canResearch(eTempTech, true) && GET_TEAM(GET_PLAYER(pDeadUnit->getOwnerINLINE()).getTeam()).isHasTech(eTempTech))
                        if (!GET_TEAM(GET_PLAYER(getOwnerINLINE()).getTeam()).isHasTech(eTempTech))
                        {
                            if (!GC.getTechInfo(eTempTech).isDisable())
                            {
                                aeAvailableTechs.push_back(eTempTech);
                            }
                        }
                    }
                }

                for (iJ = 0; iJ < GC.getNumPromotionInfos(); iJ++)
                {
                    if (pDeadUnit->isHasPromotion((PromotionTypes)iJ))
                    {
                        eTempTech = ((TechTypes)GC.getPromotionInfo((PromotionTypes)iJ).getTechPrereq());
                        if (eTempTech != NO_TECH)
                        {
                            if (!GET_TEAM(GET_PLAYER(getOwnerINLINE()).getTeam()).isHasTech(eTempTech))
                            {
                                if (!GC.getTechInfo(eTempTech).isDisable())
                                {
                                    aeAvailableTechs.push_back(eTempTech);
                                }
                            }
                        }
                    }
                }

                bValid = (aeAvailableTechs.size() > 0);
            }

            if (eCommerce == COMMERCE_ESPIONAGE && pDeadUnit->isBarbarian())
            {
                bValid = false;
            }

            if (bValid)
            {
                aeValidCommerces.push_back(eCommerce);
            }
        }
    }

    if (aeValidCommerces.size() > 0)
    {
        iRoll = (CommerceTypes)GC.getGameINLINE().getSorenRandNum(aeValidCommerces.size(), "Pillage");

        eCommerce = aeValidCommerces[iRoll];

        iCommerce = pDeadUnit->getCommerceForLoss(eCommerce) + GET_PLAYER(getOwnerINLINE()).getBaseCommerceFromUnit(eCommerce) + getCommerceFromWin(eCommerce);

        iCommerce *= std::max(0, (GET_PLAYER(getOwnerINLINE()).getCommerceFromUnitModifier(eCommerce) + 100));
        iCommerce /= 100;

        iCommerceVariable = (GC.getGameINLINE().getSorenRandNum(iCommerce, "Commerce Variable") * GC.getDefineINT("PILLAGE_COMM_VARIABLE_PERCENT"));
        iCommerceVariable /= 100;

        iTotalCommerce = iCommerce + iCommerceVariable;

        if (iTotalCommerce > 0)
        {
            int iRollTech;
            switch(eCommerce)
            {
            case COMMERCE_GOLD:
                GET_PLAYER(getOwnerINLINE()).changeGold(iTotalCommerce);
                szBuffer = gDLL->getText("TXT_KEY_MISC_GOLD_FROM_UNIT", iTotalCommerce, GC.getCommerceInfo(eCommerce).getChar(), GET_PLAYER(pDeadUnit->getOwnerINLINE()).getCivilizationAdjectiveKey(), pDeadUnit->getNameKey());
                gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE());
//                gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE());
                break;
            case COMMERCE_CULTURE:
                if (pNearestCity != NULL)
                {
                    pNearestCity->changeCulture(getOwnerINLINE(), iTotalCommerce, true, true);
                    szBuffer = gDLL->getText("TXT_KEY_MISC_CULTURE_FROM_UNIT", iTotalCommerce, GC.getCommerceInfo(eCommerce).getChar(), GET_PLAYER(pDeadUnit->getOwnerINLINE()).getCivilizationAdjectiveKey(), pDeadUnit->getNameKey(), pNearestCity->getNameKey());
                    gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE());
                }
                break;
            case COMMERCE_RESEARCH:
                iRollTech = GC.getGameINLINE().getSorenRandNum(aeAvailableTechs.size(), "Choose Tech");
                eRewardTech = aeAvailableTechs[iRollTech];

                if (eRewardTech != NO_TECH)
                {
                    if (GET_PLAYER(getOwnerINLINE()).getCurrentResearch() == eRewardTech)
                    {
                        iTotalCommerce *= GC.getDefineINT("CURRENT_RESEARCH_CONQUEST_TECH_PERCENT");
                        iTotalCommerce /= 100;
                    }

                    GET_TEAM(getTeam()).changeResearchProgress(eRewardTech, iTotalCommerce, getOwnerINLINE());
                    szBuffer = gDLL->getText("TXT_KEY_MISC_ACQUIRE_RESEARCH_FROM_UNIT", iTotalCommerce, GC.getCommerceInfo(eCommerce).getChar(), GET_PLAYER(pDeadUnit->getOwnerINLINE()).getCivilizationAdjectiveKey(), pDeadUnit->getNameKey(), GC.getTechInfo(eRewardTech).getTextKeyWide());
                    gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE());
                }
                break;
            case COMMERCE_ESPIONAGE:
                if (!pDeadUnit->isBarbarian())
                {
                    GET_TEAM(getTeam()).changeEspionagePointsAgainstTeam(GET_PLAYER(pDeadUnit->getOwnerINLINE()).getTeam(), iTotalCommerce);
                    szBuffer = gDLL->getText("TXT_KEY_MISC_GATHERED_INTELLIGENCE_FROM_UNIT", iTotalCommerce, GC.getCommerceInfo(eCommerce).getChar(), GET_PLAYER(pDeadUnit->getOwnerINLINE()).getCivilizationAdjectiveKey(), pDeadUnit->getNameKey(), GET_PLAYER(pDeadUnit->getOwnerINLINE()).getNameKey());
                    gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), true, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_PILLAGE", MESSAGE_TYPE_INFO, m_pUnitInfo->getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_WHITE"), getX_INLINE(), getY_INLINE());
                }
                break;
            }
        }
    }
}
/*************************************************************************************************/
/**	Food from Animals							END												**/
/*************************************************************************************************/